If you manage to restrict yourself to only solving small problems (THIS is the true challenge with software engineering, in my humble opinion), then you won't ever have wasted too much time if (when) you need to reset.
Greenfield, absolutely design up front you lucky devils, but iterative is the way otherwise.
I'm am the "Dave" on my current code since I was one of the first engineers on the project and the others before me have long moved to management. There is a lot I don't know about how the code works. There are dark corners we just lifted completely from an earlier project where the guy who wrote it 30 years back is retired. This is normal.
I'm fighting desperately to keep this code in shape as I don't want to go to management to ask for $$$ (billions) to rewrite it. I regret many choices. I'm making other choices in response that I fear someone will regret in 15 more years. I'm hoping to retire before then - better talk to me now because soon the people who have talked to the person who wrote the code 30 years ago will also be a memory. (the guy who write the code 30 years ago is still alive and someone has his phone number - they talk once a year about something weird to see if why is remembered)
Junior dev made to maintain some code base: "wtf, all this old code suck. People were really bad at their job".
Same dev 5 years later: "wellll, this looks bad but there must be a reason.". Usually the reason is someone sold a new feature without asking the implementers or even checking what the impacts could be. So it has to be ready yesterday and you'll never get approval to refactor or clean-up anything, until it breaks.
Iterative work in a large legacy codebase is how you end up making your large legacy codebase larger and even less understood.
Your planning should "wade into the code" from the start. I have always gotten better results by charting out flow diagrams and whiteboarding process changes than just "diving in and changing stuff".
Frankly, I'd say it's the opposite for greenfield development. Doing iterative work to build out a new product and make changes as you discover needs you didn't account for makes a lot more sense that flailing around making holes in something you don't fully understand that is tied to active business needs.
In terms of a broad population, I am not sure there is a meaningful difference, though. You can iterate on your ideas on the whiteboard or you can iterate on your ideas in code, but the intent is the same. Either way you are going to throw it all away once you have settled on what should be the final iteration anyhow.
It just comes down to where you are most comfortable expressing your ideas. Some like the visuals of a diagram, others are more comfortable thinking in code, some prefer to write it out in plain English, and I'm sure others carry out the process in other ways. But at the end of the day it is all the same.
I think this needs to be highlighted, because while I completely agree, I think it's often implicit, taken for granted, and neglected. Far, far too often I've seen code bases bloat because this never takes place. The sentiment at a lot of places seems to be, if the tests pass, ship it. Arguably, it may even be the right decision.
Ultimately what matters is the final changeset. How you get there doesn't really matter.
unless you have the old maintainer on call (I rarely did due to them leaving the company years ago) you definitely need to move slowly. rely on test suites if you are blessed with them. Submit small changes that pass tests.
BTW, nice and timely username.
That only works for greenfield projects where you have extensive experience with everything that is going to be used on that project. For all others you still learn as you go and all plans and designs need to be revalidated and updated multiple times.
I think the author is taking a wider view of "programming" than the actual writing of code as the end product. Some of the most important work I've done is spend the time to argue that something doesn't need to be done at all.
Maybe in a startup? My experience as an IC in larger, more established companies is the requirements are dictated to you. Someone else has already thought carefully about the customer ask, your job is just to implement, maybe push back a little if the requirements they came up with are particularly unreasonable.
Even an AI tool that takes a slack thread and summarizes how that thread informed the code would be cool to try.
Calling requirements gathering "programming" is just misusing a term for no good reason. By all means, include it in "software development" but it clearly isn't "programming".
Think about design and code (and functionality!) before you start coding. Think about design as well as code while you're coding. Think about design, code, and functionality while you're testing.
You should spend time thinking about stuff beforehand, sure, but getting your hands dirty is also going to reveal things.
Or am I. The typical engineering savant omniscient to all future past and present engineering roadblocks fixed by “Just”(TM) thinking about it beforehand. I expect this from bay area mid level not someone with credentials.
Strange because I agree with so much more of the article
Something I do a lot, and even more with the LLMS, is that I make `scratch` projects where I sketch code over and over (and maybe make mockups in Keynote or similar, make some notes, etc), then write from scratch again in the real codebase.
The statement sounds like something out of a book on the waterfall method of software development.
Your first draft may be qualitatively an MVP, but it's still just a theory of a final product you want, which requires a lot of iterative building before you get to that.
As such, there's no way to not shift between code and design, especially when business requirements are involved and which themselves may change over time.
Sounds similar to https://en.m.wikipedia.org/wiki/Curry–Howard_correspondence.
I now have a few decades of experience doing technical work, running startups, teams, doing consultancy, etc. Coding is my way of getting hands on. It's quicker for me to just prototype something quickly in code than it is to do whatever on a whiteboard. I always run out of space on whiteboards and they don't have multi level undo, auto completion, etc. They really suck actually. I avoid using them.
Of course, I sometimes chin stroke extensively before coding; or I restart what I'm doing several times. But once I have an idea of what I'm doing in my head, I stub out a solution and start iteratively refining. And if I'm stuck with the chin stroking, the best way to break through that is to just start coding. Usually, I then discover things I hadn't thought about and realize I don't need to over complicate things quite as much. This progressive insight is something you can only gain through doing the work. The finished code is also the finished design; they co-evolve and don't exist as separate artifacts.
The engineering fallacy is believing that they are separate and that developers are just being lazy by not having designs. Here's a counter argument to that: we don't build bridges, rockets, expensive machines, etc. Our designs compile to executable code. Physical things have extensive post design project phases where stuff gets built/constructed/assembled. Changing the design at that stage is really expensive. For software, this phase is pretty much 100% automated in software. And continuous deployment means having working stuff from pretty much as soon as your builds start passing. Of course refactoring your design/code still is important. You risk making it hard to evolve your software otherwise.
The process of designing a bridge is actually more similar to developing software than the process of constructing one. The difference is that when you are done with the bridge design, you still have to build it. But it's a lengthy/risky process with progressive insights about constraints, physics, legislation, requirements, etc. Like software, it's hard to plan the design. And actually modern day architects use a lot of software tools to try out their designs before they hand them over.
Just some simple insights here. There is no blue print for the blue print for either bridges or software. Not a thing, generally.
Sometimes the exploration is the design process.
He might have meant design, and I'm not sure about that.
But the other thing i think of is: Understanding the problem.
It's hard to do too much of that before you start coding, and easy to do too little.
It overlaps with design to some extent, because once you understand the problem better, some designs will naturally seem inappropriate or better -- without having to spend time allocated to "designing" necessarily, just when you design you're going to come up with things that work a lot better the better you understand the problem you are trying to solve.
How the stakeholders see it, and what's really going on, and why it's a problem, and what would make an acceptable solution, and what the next steps down the road might be.
Programming is specifically about the authorship of code.
I have an extra ten years on you and couldn't agree more.
There are two jokes:
- A few months of programming can save weeks of design.
- A few months of design can save weeks of programming.
Inexperience is thinking that only one of these jokes is grounded in truth.
Recognizing which kind of situation you're in is an imperfect art, and incremental work that interleaves design with implementation is a hedge against being wrong.
- One hour of planning saves ten hours or programming...
- and one hour of research saves ten hours of planning.
You can also invert it:
- Ten hours of programming saves one hour of planning...
- and ten hours of planning saves one hour of research.
If the planning is done with 5 or more people in a meeting, there still might be some time savings...
Having to write something once, just write it.
Having to write something twice with small differences, think about it.
Having to write something three times? Consider refactoring.
But it basically sounds like waterfall development, which is a reasonable approach in certain contexts.
But this thinking doesn't really make sense for any of the projects I work on.
Nah.
I (16+ years developer) prefer to iteratively go between coding and designing. It happens way too often that when you're coding, you stumble across something that makes you go "oh f me, that would NEVER work", which forces you to approach a problem entirely differently.
Quite often you also have eureka moments with better solutions that just would not have happened unless you had code in front of you, which again makes you approach the problem entirely differently.