91 comments

[ 3.8 ms ] story [ 198 ms ] thread
I think this is a good reframing of Gall's Law for junior devs. The problem is, it's hard to put in practice if you don't know what the shape of the thing your building should be. That may actually be a non-trivial problem for a junior dev.
Experience has led me to believe that if they cannot do it this way, it is unlikely they can do it any way.
That's usually how I go about things too. It's annoying that a lot of the new crop of youtube programming videos skip these steps. I've seen a few "How to write X using Y" videos that basically write the whole thing from top to bottom one line at a time.

https://www.youtube.com/@JustForFunc and https://www.youtube.com/@fasterthanlime are good exceptions to this. I want to see the process of building out something complicated one bit at a time, including all the mistakes and dead ends.

This Raymond Chen guy should probably look into what debuggers are available on his platform of choice, he could save time by avoiding all this printf() style debugging.
Why is printf() style debugging supposed to be a bad thing if done properly? Are you of the opinion that one is supposed to use either/or of these approaches rather than using each approach for different situations to supplement each other?
for context, raymond wrote significant parts of windows going back to the 80s, and tveita knows that
Printf style debugging is very nice. I like it more than actually using the debugger in a lot of cases.
This is "printing instead of doing an action". That is not the same as debugging. Also, lightweight printf debugging is often more appropriate than using an unwieldy debugger.
> Also, lightweight printf debugging is often more appropriate than using an unwieldy debugger.

Then use a good one! :)

This is tongue in cheek, of course, but think about steps 2 and 3; this is where you want to verify that you understand when the method is called and what it gets as input. The method might receive six nested structs as arguments, how many tries does it take you to print all the relevant information? Does what you're trying to print have a useful string representation?

Set a breakpoint in your Invoke method. Inspect the arguments as deeply as you need to. Check the stack to see where the method is actually being called from. Verify that you can access any other objects you need and that they are in a sensible state. One good breakpoint can save you dozens of edit-compile-run cycles.

printf debugging shines when you need to investigate a property over many individual calls - What array sizes is this function being called with? At what point does this optimized calculation diverge from the reference implementation? Are functions A and C ever called in succession without B being called in between?

Fair enough, there's something to say for both sides. When using an IDE, I do often launch into the debugger immediately. Then again, using printf means you start out with a service that already logs all requests; you can commit that code, which you generally can't do with debugger breakpoints. I'm sure there are more arguments either side.
"Bringup" of a complicated build or deployment system can consume quite a lot of work to "do nothing". Not unusual with a new FPGA system to spend days trying to blink an LED, or a new 3D system to get a single triangle to display.
or a new 3D system to get a single triangle to display

The first hardware-accelerated 3D API I used was the first version of Direct 3D in 1996. It took days to get get single triangle.

Carmack described it well:

https://www.bluesnews.com/archives/carmack122396.html

Direct-3D IM is a horribly broken API. It inflicts great pain and suffering on the programmers using it, without returning any significant advantages. I don't think there is ANY market segment that D3D is apropriate for, OpenGL seems to work just fine for everything from quake to softimage. There is no good technical reason for the existance of D3D.

...

Many things that are a single line of GL code require half a page of D3D code to allocate a structure, set a size, fill something in, call a COM routine, then extract the result.

I remember as a kid trying to get into D3D to do basic 3D rendering of a scene, stumbling and failing, and then trying to do the same thing with OpenGL, and it being simple and sane. I wonder where all of that unnecessary incidental complexity came from; was it from trying to make D3D sufficiently interconnected with other MSFT Windows APIs and the surrounding ecosystem?
Same exact experience when I got my first Voodoo3, I spent weeks trying to figure out D3D from DirectX/MSDN's docs (was it even MSDN at the time?), and I don't think I ever got it to render a single triangle.

I was pretty defeated for a while, took me months to get motivated to try it again using OpenGL 1.1, and it just worked. I don't know how faulty my recollection is but I think I remember it was also much easier to search the web for tutorials/discussions about OpenGL than D3D at the time.

(comment deleted)
It is really funny how the official Vulkan tutorial is hundreds of lines of code just to display a dang triangle.

It's all justifiable of course, and Vulkan actually isn't too bad if you just want to push your own vertices within an engine where someone else has already written all that scaffolding.

This also can be articulated as a sort of incremental TDD.

- Write the scaffolding test to call the new "thing"

- Add basic assert to check your thing was called with right input

- Add more logic to "thing"

- Incrementally add more asserts to check for output, side-effects etc.

This is classic TDD, right? Certainly this is the approach taken by Beck in his book.
I must confess, i never read the original book/paper, just about it from various sources. I was under the impression that in "proper" TDD you always try and write the test first; so as not to taint your tests with un-necessary implementation details

In my steps above, i was switching the order in between 3 and 4. Adding logic to "thing" first and then updating the test to match; mocking and patching my way across. So implementation first and tests later. Lazy TDD as another commenter mentioned.

> I must confess, i never read the original book/paper, just about it from various sources. I was under the impression that in "proper" TDD you always try and write the test first; so as not to taint your tests with un-necessary implementation details

It's well worth reading, very short (and pretty funny also).

But yeah, the approach he suggests is to write the minimal failing test, then make it pass, then repeat. Red, green, refactor is the short form of his approach.

But your misconception appears to be incredibly common, I've heard it from so many people over the years. No idea where it came from, but it's nonsense (IMO, obviously).

I do this but skip the last step, I call it ultra-lazy TDD. It's really just a toolchain/syntax/library import check.

The only time I write more actual tests is when squashing bugs.

Getting the "Hello World" to compile and run is often the most difficult part of a project. After that it's only easy incremental improvements.
Good read. This is so true, by the way, the importance getting a proof-of-principle of some end-to-end multi-step process. I've sometimes described this as a breadth-first solution, which often makes sense to generic business types.
Sorry, wouldn't this approach of going all the way to the end, while ignoring as much as you can on the way, actually be a depth-first solution?
I think the idea is that they didn't ignore as much as you can along the way. They spent a lot of time on each of their foundations, completing (to some degree) each layer before moving onto the next.

> It had passed through our new modeling tools, through two different intermediate converter programs, had been loaded up as a complete database, and been rendered through a fairly complex scene hierarchy, fully textured and lit

They didn't do the bare minimum modeling without tooling, didn't hack together (or avoid making) barely enough converter programs, they didn't hack together an in-memory database as a prototype, and they didn't do the bare minimum rendering to show a triangle.

They built out a fully working system, layer by layer, the entire breadth of each layer, until they got to the rendering and display layers. At the end of it, they got a triangle. But, since they put in all of the effort to build a strong foundation, the second triangle is 1000x easier to make than the first.

Haha. I worked on a manufacturing monitoring app. It communicated status from plant floor controllers (PLC) to turn boxes on the screen different colors.

The operators wanted a certain box to "turn green", and they told a coworker about it.

So he hardcoded it to green, not using the status from the PLC.

The thing is, he was already working on the request, but getting the communication up and running for the PLC is quite involved, so to stop people from bugging him he just "turned it green"

*PLC means programmable logic controller, aka simple and predictable industrial computer with lots of I/O

Truly, unproductively fucking around with broken tools and terribly-designed libraries/APIs/SDKs is like 80% of the job.
I tried to build a Hello World java console app last year from notepad and command line. I'm sure I could have got it to work, but it's just so much easier to let the IDE do everything for me that I gave up.
Are you trolling? That's 4 lines of code any Java dev can type from memory.

package foo;

public class Hello {

public static void main(String[] args){

System.out.println("hi world"); } }

As for the build and run,

javac foo/Hello.java

java foo.Hello

That's it. This is covered in chapter one of any Java book.

Am I misunderstanding your point or something? It sounds like you are complaining that Java is hard to get a simple hello world running without IDE help, but I must surely be misunderstanding you, because that would only be the case if you refused to do even the most cursory reading beforehand

Not trolling. The last time I had done this was in the Java 1.0 days.

I would invite you to re-read your code and see how many different things you need, and how they are expressed differently in different places.

"Any Java dev" - I'm not a Java dev. I'm a dev who sometimes writes Java. I am not good at remembering equivalent commands across languages. For instance, there's not much call to remember System.out.println when writing Spring Boot apps.

Different people have different skills. For instance, some people can communicate without insulting people. This is a valuable skill to grow a career.

Also, there are things not shown, like environment variables.

I love your comment as an example of "This is so simple, there are only 20 things that you have to get perfect, any idiot can do that"

Yeah, I'm sure it's hard, if you try to do it from memory and haven't done it in years. You could just take 5 min to refresh your memory by looking at the first 3 pages of any Java book though. Or stack overflow for goodness sake. "Hello world in Java"

This is an example of making things harder on yourself for no reason and then complaining about your tools instead of your own artificial restrictions. There's no shame in looking some syntax up if you haven't done it in many years.

You said there were 20 things in there but I only count two unique values that aren't just boilerplate you could look up in a minute-- the package name and class name.

I just get tired of these kinds of superficial complaints about java "lol hello world takes 4 lines instead of 1" -- that barely affects any program that's more than 20 lines long. I just think you're part of the generation that grew up making fun of Java and it's just reflexive at this point. But, it's unfair.

Compare to a language like ruby -- hello world is one line but I have to learn a bunch of weird symbols

Lol, that said, the latest Java edition now has a way to avoid the public class business so your hello world can just be 3 lines, one of which is the closing brace. They did it to shut up these kinds of trivial complaints.

Agreed. Modern Java is nice to work in. And to your point, I wouldn't know how to write even the single Ruby or Python line without looking it up since I don't use those every day. Though, I could cycle through print, println, printf, etc...
` package foo;

public class Hello {

public static void main(String[] args){

System.out.println("hi world"); } } `

#As for the build and run,

javac foo/Hello.java

java foo.Hello

---

Structure

You need: a package*, a class*, and a main method*

3

Code

The package needs to match the folder* : 1

The class needs to be public* and match* the file name; Main method needs public* and static* and take an array of String args*; you need to remember the call to output to console* : 6

Build and Run

Have to remember javac* and java* : 2

javac and java have to be available when you call them

0 - 10 [10 if you have corporate IT managed machine] (I'll call this 1)

Remember where to put the package for each call : 2

---

So I only got 15. I could have probably got more if I tried. Just because each of those 15 things is trivial by itself, does not mean you can ignore them.

I got to do 'the algorithm game' with middle-schoolers. I was the "Peanut Butter and Jelly Sandwich Robot". I took their instructions literally. It was a hoot. It's less fun when the computer isn't trying to help you.

Assuming you have Java installed. And it's on the path.

That may not sound like much, but it's the kind of thing that is incredibly hard to figure out if you don't know what the problem is. Command lines are kind of unforgiving. When something is missing, the errors are often unhelpful. And if your next crack at it doesn't work, you get the identical error.

Googling stackoverflow isn't going to help, either.

This isn't supposed to be a major challenge. But it can really throw off a beginner. And even an experienced developer will feel stupid to have to say, "Sure, I can program in 30 languages, but I don't know how to install the FooLang compiler."

I like how people take this in different ways. For me, it is simply - compile often. Although, sometimes if I'm feeling greedy I won't compile for quite a long time.
There's a time and a place for hackathon-style coding.

But I find that I take a similar approach to Chen. Maybe not quite so rigorous.

- Start with a console app (actually I always keep a console app in the solution for isolating bits of code I want to debug)

- Scaffold the part where said code needs to go

- Once the code from step 1 is ready, stick it in the scaffold and debug until it looks good

- Work on further tests (load test, code coverage, variety of inputs)

> Once the code from step 1 is ready, stick it in the scaffold and debug until it looks good

One thing that has stuck with me from Steve McConnell’s “Code Complete” is his use of PDL (“Program Description Language” - I think).

The general idea is to write everything out in pseudo code first (at the function or small group of functions level - _not_ the whole program or component).

My PDL is basically a slightly more hand wavy dialect of Python.

I do something similar. Sometimes in plain English - it just helps me think through the problem I am trying to solve. Sometimes I use diagrams instead.

I omitted this step in my prior post, which only described the coding aspect.

But don't get me wrong: I'm not a great programmer. =)

Almost boils down to my approach: write a few lines, test. Never write more than a few lines without making sure it still compiles, runs, and does what you intended. I almost never use a debugger. Just a terminal or log file output, an editor, and a Makefile.
This is me, exactly. I'm finding myself really liking Rust for this reason.

Although back in the day I was very productive with a Lisp REPL environment, although I still used the 'write-a-little-bit-and-test' approach.

Back when I was doing a lot of full time dev, my approach was to figure out how to build Hello World (usually the device driver equivalent) and then debug it and then start for real. But always started with how to build it and debug it.
Other good nothings:

Can you check in even a tiny change to the source-code repository? A new project's first commit often triggers a slew of politics: wait, you're building what? Where's your design? Who approved this? Why are you naming it this and not that? We already built this; why are you building a second one?

What's your installer story? For installable software, do you know how to produce the installer for it? Too often the installer work is left until just before launch, at which point it's way too late. For a service, do you know how to deploy anywhere but localhost so your team can start doing internal demos?

Can anyone besides you build your hello world code? The release team often has their way of doing things, and it's not what Visual Studio spits out from its new-project template. Might as well integrate early, rather than wasting time solving problems for a build system you were never going to use.

That all sounds wildly dysfunctional. I've worked in startups with single digit engineering teams, up to massive corporations with tens of thousands of employees. I have never faced this sort of bullshit. I'm not even sure how I would respond to someone asking me, "wait, you're building what? Where's your design? Who approved this? Why are you naming it this and not that? We already built this; why are you building a second one?" but I can be sure that whatever came out of my mouth would be step 0 of finding a new place to work.
Sure, some of that sounds like "red tape". But avoiding needlessly duplicated functionality seems like a rather noble goal to me, one that can save everyone a great deal of maintenance effort in the future.
It's making blanket assumptions that a) the question asker knows better, and b) that no one bothered to think of any of this to begin with. That's not a functional way to approach organizational problems like teams building the wrong thing. Never mind that, I'd wager oftentimes the IC standing up a new repo isn't the right tree to bark up anyway.

FWIW, I personally start new projects with a Software Design Intent document that explains what we're attempting to do and why with full disclaimers about what we do and don't currently know. Maybe I've just managed to hedge these people out.

> Software Design Intent document

That's great. But having written it doesn't mean that everyone has read it. And not everyone who has read it will agree with it. Or maybe the person who you thought would champion it has left the company. Or maybe the world has changed since you wrote it. You've probably heard the expression "no business plan survives first contact with customers." A corollary, in anything but an extremely top-down organization, is that version 1 of your planning doc is unlikely to perfectly describe the final product.

> a) the question asker knows better, and b) that no one bothered to think of any of this to begin with

Eh, that's assuming a fair amount of antagonism on both sides. Most people are reasonable and rational, and after the initial "WTF? Are you crazy?" handshaking, everyone can get on the same page. But that process takes time. If your first contact with a downstream person/team/group is right before your 1.0 is supposed to ship, then you're more likely to treat them as a roadblock. If you instead involve them early, get the WTF moments out of the way, and take the time to develop a relationship, then you've turned a potential roadblock into a stakeholder and advocate, and your SDI becomes a true representation of consensus, rather than a bludgeon.

> That's great. But having written it doesn't mean that everyone has read it.

It's just describing the intention of the team at the onset. Nothing more. I will not update this document once things get really rolling, that's why we have design documents elsewhere. What I personally do with this thing is I put a checklist of "approvers" at the bottom and I send an e-mail to them all asking them to review it and give their nod of approval or otherwise.

FWIW I'm in agreement with everything else you're saying here, though.

> Software Design Intent document

Sounds like a good way to nip the creative aspect in the bud.

Sure, if a client comes to a software vendor with a clear plan, draw up good specs, requirements etc. before doing any design (or coding). Or code a quick 'n dirty proof of concept solely to hash out what exactly those requirements are. Same with existing codebase if you want to add feature X and scope of that is well defined.

But I suspect quite a few applications / projects / websites / tech startups / software libraries have started life with a "hey, that's neat. Let's take X, glue onto Y, tinker & play with it, see what we can do with that".

Small / cheap 1st iterations don't involve much wasted effort anyway. Worst case = 0 useful code but you have learned something.

When utility has shown & you get a sense of where you want it to go, then bring in the design aids for a proper v1.x, 2.x etc.

>that no one bothered to think of any of this to begin with. That's not a functional way to approach organizational problems like teams building the wrong thing

The odds you're the first one to have thought of something are [practically] zero

The odds you're the first to implement something are only slightly higher

When you find out someone else has already built 89% of what you're looking for (and 213% of what you hadn't thought of yet, because they already ran into the corner cases and what-ifs you couldn't possibly have thought of until you hit them), you can save yourself (and the organization) loads of effort by extending what's there instead of building from scratch

Maybe you're the first to think of it and first to build it

But you're probably not - and getting that early feedback from someone who sees what you're working, and says, "why are you building what Sally & Tom built last spring?" is absolutely invaluable

Better ways to go about it than impertinent and presumptuous interrogation.
> What's your installer story? For installable software, do you know how to produce the installer for it? Too often the installer work is left until just before launch

Putting on my sysadmin hat: Please do this. Please.

Think about the people who have to install and maintain your software.

Talk with real sysadmins about how they deploy software if you don't have experience doing it. Think about how you'd deploy, remove, and update it on large numbers of machines-- particularly where the users don't have administrative rights or where the machines are automatically-provisioned "cattle".

Also, use off-the-shelf installer systems, if you can, versus rolling your own. The maintainability will be a lot better.

I thought my software should randomize config and install locations for security reasons? And also that I should add salt to binaries so that each binary has a unique hash. Also it should prompt users to change passwords every 72 hours and lock them out after two incorrect tries. Also, for database connections, it should require the connection to the database be on a non-default port. Also, it should not be possible to administer over SSH, only over telnet.
Or at least do as portable as possible. Just copy and paste a folder, and `dot net run` will be amazing....
Or, stealth mode: Check it into a repo, but a private one. Nobody else even knows you're building the thing until you can demonstrate utility. Avoids all the bullshit.

Not saying it's better, but it can be the difference between achieving something and nothing.

It's a balance, for sure. It's great to get early feedback on both technical and product aspects of a project. But as you say, feedback can also kill the project if it's the straw that breaks the camel's back. Or it can be the support that keeps you going when you're thinking of giving up.
When I am starting a new project I have learned to identify the unknowns.

"I don't know how to do X, Y and Z."

Before I begin working on the real solutions for X, Y & Z I start by making a test program that does X. It's ok if it requires a ton of scaffolding, or canned data... the important thing is to do X. Then I do the same for Y & Z.

Now that I understand the problem I do a software design. I do this on paper and I purposely do it super quick and not caring about how neat it is... and I throw away designs rapidly as I iterate and improve. Eventually the paper crumbling slows down and I approach a real design.

This is finally the point that I can write "real" code. The unknowns are gone and all the software design iteration happened on paper.

Very interesting. Your "paper crumbling" iterative process is very similar to an LLM iteratively refining information within a context window (the paper is the context window).
This is similar to or the same as "throw away the first thing you did" often this can be throw away the second, too, if you want.

I totally agree, and I work in a similar way. I find that the time I gain down the road drastically makes up for the time spent on the prototypes.

This doesn't apply to every problem, mind you - I only advise this type of working either if you really want to understand something, or if you have a good hunch it is going to be used for a while (or may be). One off scripts, there's not much gain - just get them working. Code that is part of a system, absolutely. It should be done this way. Throw it away - and maybe throw it away again.

> the important thing is to do X

... or you think it's good enough, put it in prod, claim the impact, and move to the next problem.

"Make it work, make it right, make it fast"
I am currently writing a tool that’s glue between network calls (downloads) and disk (saving those). Fundamentally, it has to be async. A sync version would be slower by probably two orders of magnitude, for no good reason. Real threading would be overkill, on the other hand.

So I’m kind of making it fast first, or at least laying the foundation for it. Async has to be in place from the start due to function colouring. I spent a while being entirely “unproductive”, setting it up.

To be contrarian, one could argue that "make it work" includes building in a performant way from the start. In my mind "make it fast" is about optimization!
Embedded robotics firmware version: Show me that you can deploy an update to BlinkyLED, via the cloud manager, over LTE, to the robot with rock-solid reliability every damn time. Step two: update the bootloader over the wire without bricking the robot.
Related truisms I've come to:

* Watch the test fail first. Write a test FooMethod_Should_Do_X. Confirm it fails. If it passes, it means you're testing the wrong thing. Once it fails, make it pass. Once it passes, make it pretty while still passing

* The simplest thing you can do is nothing. As a developer, your first job is to talk customers down from that feature request without annoying them too badly. "What bad things happen if the app doesn't do X?", "Explain the business value of X to me. About how much time or money will this save?".

* This applies not just in code. In personal interactions, saying nothing or doing nothing is often better than prematurely doing the wrong thing. There is a time to say and do something, but it is usually later than we think and not on social media.

Your 2nd point rubs me the wrong way, though it could just be the wording.

Depending on the organization, by the time it got to you, there may have already been discussions about scope and business need.

Unless you're an SME, your evaluation of what is needed is not better than that of those who are requesting the work. Sure, your knowledge of the effort is better, but that's not the same thing.

There's a decent chance you're going to come across as difficult to work with and then you're going to build a solution that doesn't fully meet their needs.

I get where you're coming from, but I've spent time on the other side. Requirements take negotiation and collaboration.

You can spin the second questions as wanting to understand why this hasn't been done before, and what the current workarounds are.

It gives you some sense of the affordances you need and the current value of having done nothing so far.

It also helps with prioritization - is it a must, a should, a could, a wish?

To be sure, part of the challenge for me on that one is to ask it while not being a jerk. Yes, it’s a negotiation. Maybe you and I work in different circles, but in my experience people ask for features they don’t need all the time. They have a business problem, ask for what they think is the technical solution, but may not know the technical options available to solve the business problem. They may ask for a 500 page report so they can find a customer that meets x criteria, but really, better search would help them more. I had a customer sink hundred thousands into cryptographic digital signatures. I suggested the “business analyst” and upper management discuss with legal, and indeed in this case a checkbox sufficed instead.

As a dev I like to say my job is to translate English into nerd. Non- or semi- technical people should communicate the business problem and then together we’ll work towards the best solution. Sometimes the solution is code.

> Start with something that does nothing. Make sure you can do nothing successfully. Only then should you start making changes so it starts doing something.

Excellent advice!

Just last week I did JSON transformations in a succession of little Node JS programs that are chained by pipe. Each program does one step of the transformation; it starts its life by outputting what it receives, then evolves to actually manipulate data.

It's an approach that's quite safe and rarely breaks, and when it breaks it's easy to find where the problem is.

How many proof of concepts must a project knock down, before you start to integrate. (with profuse apologies to Bob Dylan)

This is a very good thing to keep in mind when estimating.

I wish people who wrote these things would give a bit more context. Seems like the great temptation when writing about programming is to assume that your kind of work is the only kind of work any programmer ever does.

I write tools that help me test things. There are a lot of people like me who don’t work on big systems or write production code. Our priorities are different.

I need to duck tape a thing to another thing quickly. I happily accrue tech debt because getting my testing done today (not regression testing, but primary testing) is paramount. Later I will declare bankruptcy (abandon the code).

I work alone, mostly.

The dynamics change when I work with other guys, or when my software has to serve as a persistent framework into the future.

I’m just saying there are a lot of programmers like me. We are also interested in good craftsmanship— but we operate in a “battlefield” context, not a drawing room context.

He started the article with: "When building a new thing, a good first step is to build a thing that does nothing."

and later he adds: "Too often, I see relatively inexperienced developers dive in and start writing a big complex thing"

He is advicing to before start building something, make sure that the context is rightly settled.

the blog post illustrates a failure of mentoring junior(or even midcareer) engineers (EDIT2: but doesnt admit it - for shame!). EDIT: no one (regardless of their tenure or pedigree) should be left to their own devices to paint themselves into a corner.
baby steps baby!

this is great strategy for debugging & so code reviewers have an easier time reviewing your incremental changes.

On newer teammates, I usually reject code reviews if they don't follow these practices (if the company's engineerimg culture is compatible with it)

I have several friends, programmers, who brag about their big concentration powers.

But can you turn it off?

To concentrate one on thing is to ignore 1000 things. If that can't be turned off, becomes habitual, permanent, fades to invisibility as constants and habits generally do, one might be suffering from a massive distortion of perspective and not even know it.

What does this comment have to do with the article?
I'm telling you that your bread and butter contains a bit of rat poison.
Did you maybe mean to be commenting on the article about attention spans?
You should stop framing your statements as questions.
I feel like this is one of the things beginner programmers eventually figure out on their own without having to be told about it, otherwise they'd never be able to complete fairly basic programs but large programs which touch a lot of systems.

You'd have to be really new to write a bunch of code without ever testing it working incrementally, likely because you've never encountered it before. A couple of painful debugging sessions will quickly make you realize you need to test your assumptions one by one in the right order if you are to ever have a chance of making an unknown program (i.e. a program you are writing for the first time) work. All the stars have to align, because one wrong error will throw everything right off. Debugging is the act of visiting each possible source of error and validating it works. The best way to do this is to build the program incrementally (which again, I expect programmers to quickly realize).

This is probably good advice, generally speaking. But I know there are exceptions to this. What I figured out very quickly is that most people end up needing to take this approach due to the problems you described.

I've been programming professionally for 10 years. And even in my early years, I could code all day without running and normally it works as I expected or if an error occurs it's quick to fix.

Sorry if that sounds like bragging, but I'm sure there are others out there that are like this- just saying it's not an absolute truth, but I believe it to be generally true.

> The program hasn’t even gotten to the point where it can comprehend the possibility of executing that line of code. I mutter to myself, “How did you let it get this bad?”

I support a lot of scientists-who-sometimes-code, and I get this all the time. They bring me in and show me the 5000 line Python (or Matlab if I'm unlucky) script they've written. "It doesn't work."

Turns out they've written 5000 lines of code without having ever once tried to run a smaller piece while they were writing it. Not even once. They write the whole thing and THEN when it doesn't run on the first try, they don't know what to do.

Especially true when working on an unknown code base.

I frame up small projects that replicate the key parts of the software I need to interact with.

So often you find yourself trying to integrate with outdated code vases full of unknown dependencies and customisations that look nothing like the docs or sample code.

Even the smartest people can feel overwhelmed!

Gives your confidence when you can get a feature working from a fresh project!