18 ms·
Before you try to do something, make sure you can do nothing
- dasil003 3y agoI 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.
- mannykannot 3y agoExperience has led me to believe that if they cannot do it this way, it is unlikely they can do it any way.
- justinsaccount 3y agoThat'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 https://www.youtube.com/@JustForFunc and https://www.youtube.com/@fasterthanlime 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.
- tveita 3y agoThis 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.
- l33t233372 3y agoPrintf style debugging is very nice. I like it more than actually using the debugger in a lot of cases.
- yowlingcat 3y agoWhy 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?
- kragen 3y agofor context, raymond wrote significant parts of windows going back to the 80s, and tveita knows that
- gpvos 3y agoThis 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.
- tveita 3y ago> 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?
- gpvos 3y agoFair 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.
- pjc50 3y ago"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.
- zgluck 3y agoor 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 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.
- yowlingcat 3y agoI 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?
- piva00 3y agoSame 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.
- sidmitra 3y agoThis 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.
- disgruntledphd2 3y agoThis is classic TDD, right? Certainly this is the approach taken by Beck in his book.
- sidmitra 3y agoI 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.
- disgruntledphd2 3y ago> 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).
- sneak 3y agoI 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.
- DaOne256 3y agoGetting the "Hello World" to compile and run is often the most difficult part of a project. After that it's only easy incremental improvements.
- skitter 3y agoThe "black triangle moment": https://web.archive.org/web/20050306071700/http://www.rampantgames.com/blog/2004/10/black-triangle.html https://web.archive.org/web/20050306071700/http://www.rampan...
- KineticLensman 3y agoGood 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.
- falcor84 3y agoSorry, 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?
- xboxnolifes 3y agoI 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.
- yellow_lead 3y agoI 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.
- michaelfeathers 3y agoI've always thought of this as being like proof by induction: start with the basis case.
- readthenotes1 3y ago0, 1, N
- HPsquared 3y agoThiel's book "Zero to One"
- RajT88 3y agoThere'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)
- pbourke 3y ago> 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.
- RajT88 3y agoI 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. =)
- SoftTalker 3y agoAlmost 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.
- KineticLensman 3y agoThis 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.
- aikiplayer 3y agoBack 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.
- sowbug 3y agoOther 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.
- scruple 3y agoThat 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.
- valleyer 3y agoSure, 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.
- scruple 3y agoIt'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.
- dicroce 3y agoWhen 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.
- thelastparadise 3y agoVery 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).
- roflyear 3y agoThis 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.
- yodsanklai 3y ago> 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.
- reese_john 3y ago"Make it work, make it right, make it fast"
- diarrhea 3y agoI 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.
- extasia 3y agoTo 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!
- dbcurtis 3y agoEmbedded 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.
- shireboy 3y agoRelated 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.
- mcdonje 3y agoYour 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.
- kthejoker2 3y agoYou 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?
- shireboy 3y agoTo 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.
- bambax 3y ago> 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.
- csours 3y agoHow 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.
- satisfice 3y agoI 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.
- ZeroClickOk 3y agoHe 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.
- pizzaknife 3y agothe 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.
- gareve 3y agobaby 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)
- swayvil 3y agoI 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.
- SPBS 3y agoI 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).
- jcpst 3y agoThis 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.
- dmd 3y ago> 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.
- firecall 3y agoEspecially 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!
- emmanueloga_ 3y agoReminds me of woodworking: 60% of a project is building cutting jigs, 30% is for cutting, 10% is for gluing and fixing the parts together.
- acters 3y agoSpeaking directly about the title, it is true. Once you start something, it is the most important thing. It can be dropped at any moment if desired. However, the optimal path is towards completion. This means that you are unable to do something else. Thereby planning to do nothing else. You have to make sure you can focus on your task to completion. Otherwise, you will end up having to alternate tasks. Surprisingly, we alternate tasks constantly. Mainly, it is because of boredom, time constraints, or lack of capability(knowledge, power, resources, etc).
- shermix011 3y agoReminds me of an article from Mitchell Hashimoto: https://mitchellh.com/writing/building-large-technical-projects https://mitchellh.com/writing/building-large-technical-proje...