Programming Is Mostly Thinking (2014)
agileotter.blogspot.com
agileotter.blogspot.com
"Really good developers do 90% or more of the work before they ever touch the keyboard;"
While that may be true sometimes, I think that ignores the fact that most people can't keep a whole lot of constraints and concepts in their head at the same time. So the amount of pure thinking you can do without writing anything at all is extremely limited.
My solution to this problem is to actually hit the keyboard almost immediately once I have one or more possible ways to go about a problem, without first fully developing them into a well specified design. And then, I try as many of those as I think necessary, by actually writing the code. With experience, I've found that many times, what I initially thought would be the best solution turned out to be much worse than what was initially a less promising one. Nothing makes problems more apparent than concrete, running code.
In other words, I think that rather than just thinking, you need to put your ideas to the test by actually materializing them into code. And only then you can truly appreciate all consequences your ideas have on the final code.
This is not an original idea, of course, I think it's just another way of describing the idea of software prototyping, or the idea that you should "throw away" your first iteration.
In yet different words: writing code should be actually seen as part of the "thinking process".
But for the rest of us (especially myself), it seems to be more like an interplay between thinking of what to write, writing it, testing it, thinking some more, changing some minor or major parts of what we wrote, and so on, until it feels good enough.
In the end, it's a bit of an art, coming up with the final working version.
This is special because most real world systems has a lot more dependencies. That’s when experimentation is required. Because one cannot know all relevant API’s beforehand and their behaviors. Therefore the only way is to do it and find out.
Algorithms are in essence mathematical problems, therefore is abstract and should be able to be solved in the head or use pen and paper.
Reality is that most programming problems are not algorithms but connecting and translating between systems. And these systems are like blackboxes that require exploration.
This type of developer tends to prefer building software like this. There is a whole crowd of hardcore C/C++/Rust devs who eschew taking dependencies in favour of writing everything themselves (and they mostly nerd-snipe themselves with the excessive NIH syndrome, like Jonathon Blow off writing Powerpoint[1]...)
Torvalds seems to be mostly a special case in that he found a sufficiently low-level niche where extreme NIH is not a handicap.
[1]: https://www.youtube.com/watch?v=t2nkimbPphY&list=PLmV5I2fxai...
This is really important for maintenance later on. If it's too complicated now to keep in your head, how will you ever have a chance to maintain it 3 years down the line? Or explain it to somebody else?
Code also functions as documentation for the actual process. In many cases “whatever the software do” is the process itself.
In the end, I find my mental picture is still the most important. And when that fades after a while, or for code written by someone else, then I just have to go read the code. Though it may exist, so far I haven't found a way that's obviously better.
Some thing I've tried (besides commenting code) are doing diagrams (they lose sync over time) and using AI assistants to explain code (not very useful yet). I didn't feel they made the difference, but we have to keep learning in this job.
I map out on paper the logical steps my code needs to follow a bit like a flow chart tracking the change in states.
When I write code I'll create like a skeleton with placeholder functions I think I'll need as stubs and fill them out as I go, I'm not wedded to the design sometimes I'll remove/ replace etc whole sections as I get further in but it helps me think about it if I have the whole skeleton "on the page"
That sounds a bit weird. As I remember, linux developers were using semi-closed system called BitLocker (or something like that) for many years. For some reason the open source systems at that time weren't sufficient. The problems with BitLocker were constantly discussed, so it might be that Linus was thinking about the problems for years before he wrote git.
How very biblical. “And Torwalds saw everything that he had made, and behold, it was very good. And there was evening, and there was morning—the sixth day.”
I get a general idea, then start writing code; usually the "sticky" parts, where I anticipate the highest likelihood of trouble.
I've learned that I can't anticipate all the problems, and I really need to encounter them in practice.
This method often means that I need to throw out a lot of work.
I seldom write stuff down[0], until I know that I'm on the right track, which reduces what I call "Concrete Galoshes."[1]
[0] https://littlegreenviper.com/miscellany/evolutionary-design-...
[1] https://littlegreenviper.com/miscellany/concrete-galoshes/
Now I could have spent that time "whiteboarding" and it's possible I would have come close to the same solution. But whiteboarding in my mind is still guessing, anticipating - coding is of course real.
I think that as you gain experience as a programmer you are able to intuit the right way to begin to code a problem, the iterating is still there but more incremental.
An experienced programmer is also more cognizant of the importance of architectural decisions, hitting the balance between keeping things simple vs abstractions and the balance between making things flexible vs YAGNI.
Once those important bits are taken care of, rest of it is more or less personal style.
I wanted to work that way, when I was younger, but the results were seldom good.
Good judgment comes from experience. Experience comes from bad judgment.
-Attributed to Nasrudin
My only optimization of this process is to use Java and not just throw out everything, but keep refactoring. Idea allows for very quick and safe refactoring cycles, so I can iterate on overall architecture or any selected components.
I really envy on people who can get it right first time. I just can't, despite having 20 years of programming under my seat. And when time is tight and I need to accept obviously bad design, that what makes me burning out.
As I've grown older, the importance of architecture over micro decision has become blindingly apparent.
The micro can be optimised. Macro level decisions are often permanent.
The more crap you add the harder it is to fix bad architecture.
And the crap is often stuff that would be trivial to add if the bad architecture weren't there, so if you fix that you can add the feature when you need it in a week.
What I try to do is think about the classes of functionality that might be needed in the future. How could I build X feature in a years time?
Leave doors open, not closed.
I kind of imagine what the end result should be in my head (given value A and B, these rows should be X and Y), then write the tests in what I _think_ would be a good api for my system and go from there.
The end result is that my code is testable by default and I get to go through multiple cycles on Red -> Green -> Refactor until I end up being happy with.
Does anyone else work like this?
Right tool for the job, as always! The only thing I can't stand is blind zealotry to one way or the other. I've had to work with some real TDD zealots in the past, and long story short, I won't work with people like that again.
Like, I expect it should look one way but after I'm done with a few TDD cycles I'm at a state that's either hard to get there or unnecessary.
I think this is why some people don't like TDD much, sometimes you have to let go of your ideas, or if you're stuck to them, you need to go back much earlier and try again.
I kind of like this though, makes it kind of like you're following a choose your own adventure book.
* Scribbling out some basic design notes. * Figuring out the bits I'm not completely sure about * Maybe coding up some 'prototype' code to prove out the bits I'm less sure about * Repeat until I think I know what I'm doing/validated my assumptions * Put together a 'more formal' design to share with the team. Sometimes my coworkers think of things that I hadn't, so it's not quite a formality. :) * Code the thing up.
By the time I get to the "code it up" stage, I've probably put in most of the work. I've written things down as design, but nothing hyperdetailed. Just what I need to remind myself (and my team) of the decisions I've made, what the approach is, the rejected ideas, and what needs doing. Some projects need a fair bit on paper, some don't.
I would point out, though, that that part also touched understanding requirements, which is many times a very difficult process. We might have a technical requirement conjured, by someone less knowledgeable about the inner workings, from a customer requirement and the resolution of the technical requirement may not even closely address the end-users' use-case. So, a lot of time also goes into understanding what it is that the end-users actually need.
But this also makes it difficult to give accurate estimates because you sometimes need to prototype 2,3 or even more designs to workout the best option.
> writing code should be actually seen as part of the "thinking process".
Unfortunately most of the times leadership dont' see things this way. For them the tough work of thinking ends with architecture or another layer down. Then the engineers are responsible only for translating those designs into software just by typing away with a keyboard.
This leads to mismatch in delivery expectations between leadership and developers.
The prototype should provide you with cast iron certainty that the final design can be implemented, to avoid wasting a huge amount of effort.
I would say the topic is two-sided.
The first is when we do greenfield development (maybe, of some new part of an already existent software): the domain is not really well known and the direction of the future development is even less so. So, there is not much to think about: document what is known, make a rough layout of the system, and go coding. Too much investing in the design at the early stages may result in something (a) overcomplicated, (b) missing very important parts of the domain and thus irrelevant to the problem, (c) having nothing to do with how the software will evolve.
The second (and it is that side I think the post is about) is when we change some already working part. This time it pays hugely to ponder on how to best accommodate the change (and other information the request to make this change brings to our understanding of the domain) into the software before jumping to code. This way I've managed to reduce what was initially thought to take days (if not weeks) of coding to writing just a couple of lines or even renaming an input field in our UI. No amount of exploratory coding of the initial solution would result in such tremendous savings in development time and software complexity.
first is the urge to write the whole prototype yourself from scratch. Not necessary, better avoided. You should just hack some things together, or pick something close to what you want off github. Idea is to have something working. I am a big proponent of implementing my ideas in a spreadsheet, then off to some code.
Second is modern software solutions are complex (think kubernetes, cloud provider quirks, authentication, sql/nosql, external apis) and easy to get lost in the minutiae, they shroud the original idea and takes strenuous effort to think clearly through the layers. To counter this, I keep a single project in my language of choice with the core business logic. No dependencies. everything else is stubbed or mocked. It runs in the IDE, on my laptop, offline with tests. This extra effort has paid off well to focus on core priorities and identify when bullshit tries to creep in. You could also use diagrams or whatever but working executable code is awesome to have.
third is to document my findings. Often I tend to tinker with the prototype way beyond the point of any meaningful threshold. its 2am before i know it and i kinda lose the lessons when i start the next day. Keeping a log in parallel with building the prototype helps me stay focussed, be clear in what my goals are and avoid repeating the same mistakes.
fourth is the rather controversial topic of estimation. When i have a running prototype, I tend to get excited and get too optimistic with my estimates. Rookie mistake. Always pad your estimates one order of magnitude higher. You still need to go through a lot of bs to get it into production. Remember that you will be working with a team, mostly idiots. Linus works alone.
> What is really happening?
> • Programmers were typing on and off all day. Those 30 minutes are to recreate the net result of all the work they wrote, un-wrote, edited, and reworked through the day. It is not all the effort they put in, it is only the residue of the effort.
So at least there the article agrees with you.
Plenty of good developers use the code as a notepad / scratch space to shape ideas, and that can also get the job done.
And what most people can't do, such as keeping in their heads absolutely all the concepts of a theoretical computer software application, is an indication that real programmers exist on a higher elevation where information technology is literally second nature to them. To put it bluntly and succinctly.
For computer software development to be part of thinking, a more intimate fusion between man and machine needs to happen. Instead of the position that a programmer is a separate and autonomous entity from his fungible software.
The best programmers simulate machines in their heads, basically.
Yes, but they still suck at it.
That's why people create procedures like prototyping, test driven design, type driven design, paper-prototypes, API mocking, and etc.
Documentation is a good starter/unblocker but once I've got the basics down then I'll run wild in a REPL or something figuring out exactly how I want to do something.
Pure thinking planning is a good way to end up with all sorts of things that weren't factored in, imo. We should always encourage play during the planning process.
Personally, I think good developers get characters on to the screen and update as needed.
One problem with so much upfront work is how missing even a tiny thing can blow it all up, and it is really easy to miss things.
I agree. This is how I work as well. I start coding as quickly as possible, and I fully plan on throwing away my first draft and starting again. I do a fair bit of thinking beforehand, of course, but I also want to get the hidden "gotchas" brought to light as quickly as possible, and often the fastest way is to just start writing the code.
But when I do get down to writing code, it very much takes an evolutionary path. Typically the first thing I start writing is bloated, inefficient, or otherwise suboptimal in a variety of ways. Mostly it's to get the relationships between concepts established and start modeling the process.
Once I have something that starts looking like it'll work, then I sort of take the sculptor's approach and start taking away everything that isn't the program I want.
So yeah, a fair amount of planning, but the first draft of anything I write, really, code or otherwise, is something for me, myself, to respond to. Then I keep working it over until it wouldn't annoy me if I was someone else picking it up cold.
How I work:
- First I make a very general design of modules, taking into account how they are going to communicate with each other, all based in experience with previous systems.
- I foresee problematic parts, usually integration points, and write simple programs to validate assumptions and test performance.
- I write a skeleton for the main program with a dumbed-down GUI.
From that point on, I develop each module and now, yes, there's a lot of thinking in advance.
Indeed, and this limitation specifically is why I dislike VIPER: the design pattern itself was taking up too many of my attention slots, leaving less available for the actual code.
(I think I completely failed to convince anyone that this was important).
I think it's just two ways of doing the same thing.
Whether you plan before pen meets paper or plan while noodling is a matter of taste.
I hand wrote HTML forms and that was not a great plan. I made a dialog generator class in about a half hour that replaced dozens of CreatePermission.html type garbage I wrote a decade ago.
Then I break that down into small and smaller steps.
Then I hack it together to make it work.
Then I refactor to make it not a mess.
Then I learned TDD, and now I can discover the design while I code. It's a huge improvement for me!
i am not smart enough this week to debug a raytracer on paper before typing it in, if i ever was
things like hypothesis can make a computer very powerful for checking out ideas
The best explanation I've seen is in the book "The Secret Life of Programs" by Jonathan E. Steinhart. I'll quote that paragraph verbatim:
---
Computer programming is a two-step process:
1. Understand the universe.
2. Explain it to a three-year-old.
What does this mean? Well, you can't write computer programs to do things that you yourself don't understand. For example, you can't write a spellchecker if you don't know the rules for spelling, and you can't write a good action video game if you don't know physics. So, the first step in becoming a good computer programmer is to learn as much as you can about everything else. Solutions to problems often come from unexpected places, so don't ignore something just because it doesn't seem immediately relevant.
The second step of the process requires explaining what you know to a machine that has a very rigid view of the world, like young children do. This rigidity in children is really obvious when they're about three years old. Let's say you're trying to get out the door. You ask your child, "Where are your shoes?" The response: "There." She did answer your question. The problem is, she doesn't understand that you're really asking her to put her shoes on so that you both can go somewhere. Flexibility and the ability to make inferences are skills that children learn as they grow up. But computers are like Peter Pan: they never grow up.
https://www.datapacrat.com/Opinion/Reciprocality/r0/index.ht...
I'm sorry, but yout entire comment reads like a list of platitudes about programming that don't actually match reality.
> Well, you can't write computer programs to do things that you yourself don't understand.
Not true. There are many times where writing software to do a thing is how I come to understand how that thing actually works.
Additionally, while an understanding of physics helps with modeling physics, much of that physics modeling is done to implement video games and absolute fidelity to reality is not the goal. There is often an exploration of the model space to find the right balance of fidelity, user experience and challenge.
Software writing is absolutely mostly thinking, but that doesn't mean all or even most of the thinking should al always come first. Computer programming can be an exploratory cognitive tool.
> So, the first step in becoming a good computer programmer is to learn as much as you can about everything else. Solutions to problems often come from unexpected places, so don't ignore something just because it doesn't seem immediately relevant.
I'm all about generalist and autodidacts, but becomming one isn't a necessary first step to being a good programmer.
> The second step of the process requires explaining what you know to a machine that has a very rigid view of the world, like young children do.
Umm... children have "rigid" world views? Do you know any children?
> Let's say you're trying to get out the door. You ask your child, "Where are your shoes?" The response: "There." She did answer your question.
Oh, you don't mean rigid, you mean they can't always infer social subtexts.
> Flexibility and the ability to make inferences are skills that children learn as they grow up. But computers are like Peter Pan: they never grow up.
Computes make inferrences all the time. Deriving logical conclusions from known facts is absolutely something computers can be programmed to do and is arguably one of their main uses cases.
I have spent time explaining to things to children of various ages, including 3 year olds, and find the experience absolutely nothing like programming a computer.
> Software writing is absolutely mostly thinking, but that doesn't mean all or even most of the thinking should al always come first. Computer programming can be an exploratory cognitive tool.
Absolutely, explaining something to the child also can be exploratory cognitive tool.
Or at least they don't make mistakes in exceptionally novel and unusual ways until they're a bit older.
I don't see any overlapp between the two skill sets, since you do I'd be curious for examples of where you do see overlap.
I'm confident enough to tout this number as effectively true, though I should mention that no company I work with has so far been willing to delete a whole day's work to prove or disprove this experiment yet.
Long ago when I was much more tolerant, I had a boss that would review all code changes every night and delete anything he didn't like. This same boss also believed that version control was overcomplicated and decided the company should standardize on remote access to a network drive at his house.The effect of this was that I'd occasionally come in the next morning to find that my previous day's work had been deleted. Before I eventually installed an illicit copy of SVN, I got very good at recreating the previous day's work. Rarely took more than an hour, including testing all the edge cases.
When they were bought of by some bigger company, we got access to their intranet. I digged through that and found a gitlab instance. So then I just versioned my own code (which I was working on mostly on my own), documented all of it on there, even installed a gitlab runner and had a step-by-step documentary on how to get my code working. When they kicked me out (because I was kind of an asshole, I assume), they asked me to hand over my code. I showed them all of what I did and told them how to reproduce it. After that the boss was kinda impressed and thanked me for my work. Maybe I had a little positive impact on a shitty job by being an asshole and doing stuff the way that I thought would be the right way to do it.
Edit: Oh, before I found that gitlab instance I just initialized raw git repositories on their network share and pushed everything to that
Even when done with good intentions, managers being involved in code/reviews almost always ends up being net negative for the team.
There are human elements too. Even if someone has honest inputs, any (monetary or otherwise) rewards or lack of them will be attributed to those inputs (or lack of them). Overall, it just encourages bad behaviours among the team and invites trouble.
These should not happen in an ideal world but as we are dealing with people things will be far from ideal.
I think I recognise that tiny diffs that I might commit can be the ones that take hours to create because of the debugging or design or learning involved. It's all so easy to be unimpressed by the quantity of output and having something explained to you is quite different from bashing your head against a brick wall for hours trying to work it out yourself.
You can't think about what the computer should do if you don't know what the business should do.
From this perspective, it might make sense to train coders a bit like how we train translators. For example, I have a friend who is a translator. She speaks a bunch of languages, it's very impressive. She knows the grammar, idioms, and so on of a wide number of languages, and can pick up new ones like how you or I can pick up a new coding language.
But she also spent a significant amount of time learning about the pharmaceutical industry. Stuff about how that business works, what kinds of things they do, different things that interface with translation. So now she works translating medical documents.
Lawyers and accountants are another profession where you have a language gap. What I mean is, when you become a professional, you learn the language of your profession, and you learn how to talk in terms of the law, or accounting, or software. What I've always found is that the good professionals are the ones who can give you answers not in terms of their professional language, but in terms of business.
Particularly with lawyers, the ones who are less good will tell you every possible outcome, in legalese, leaving you to make a decision about which button to press. The good lawyers will say "yes, there's a bunch of minor things that could happen, but in practice every client in your positions does X, because they all have this business goal".
---
As for his thought experiment, I recall a case from my first trading job. We had a trader who'd created a VBA module in Excel. It did some process for looking through stocks for targets to trade. No version control, just saved file on disk.
Our new recruit lands on the desk, and one day within a couple of weeks, he somehow deletes the whole VBA module and saves it. All gone, no backup, and IT can't do anything either.
Our trader colleague goes red. He calms down, but what can you do? You should have backups, and what are you doing with VBA anyway?
He sits down and types out the whole thing, as if he were a terminal screen from the 80s printing each character after the next.
Boom, done.
Very true. There’s a huge difference developing in a well known vs. new domain. My mantra is that you have to first be experienced in a domain to be able to craft a good solution.
Right now I am pouring most of my time in a fairly new domain, just to get an experience. I sit next to the domain experts (my decision) to quickly accumulate the needed knowledge.
I fully agree with you. However, my experience as a software engineer with a CPA is that, generally speaking, companies do not care too greatly about that domain knowledge. They’d rather have a software engineer with 15 years working in accounting-related software than someone with my background or similar and then stick them into a room to chat with an accountant for 30 minutes.
In the comment thread, I keep seeing prescriptions over and over for the one way that programming should work.
Computer programming is an incredibly broad discipline that covers such a broad range of types of work. I think it is incredibly hard to make generalizations that actually apply to the whole breadth of what computer programming encompases.
Rather than trying learn or teach one perfect one single methodology that applies accross every sub field of programming, I think that one should aim to build a toolbag of approaches and methodologies along with an understanding where they tend to work well.
Yeah but in my country all companies have a non-compete clause which makes it completely useless for me to learn any domain-specific knowledge because I won't be able to transfer it to my next job if current employer fires me. Therefore I focus on general programming skills because these are transferable across industries.
> We do not assume that you — our reader — want to become a professional programmer and spend the rest of your working life writing code. Even the best programmers — especially the best programmers — spend most of their time not writing code. Understanding problems takes serious time and often requires significant intellectual effort. That intellectual challenge is what many programmers refer to when they say that programming is interesting.
Picked up the new edition[1] as it was on the front page recently[2].
[0]: https://www.stroustrup.com/PPP2e_Ch01.pdf
These aren't particularly interesting, and sure it's good to revisit them time and again, but these are the types of time sinks I find myself in in the last 3 companies I've worked for that feel like they should be mostly solved.
In fact, a company with a strong mindset, even if questionable, is probably way more productive. If it was set in stone we use Perl, MongoDB, CGI... I'd probably ultimately be more productive than I've been lately despite the stack.
Facebook decided to stick with PHP and MySQL from their early days rather than rewrite, and they’re still today on a stack derived from the original one.
It was the right decision IMO. They prioritized product velocity and trusted that issues with the stack could be resolved with money when the time comes.
And that’s what they’ve done by any metric. While nominally a PHP family language, Meta’s Hack and its associated homegrown ecosystem provides one of the best developer experiences on the planet, and has scaled up to three billion active users.
Should I use steel, concrete or wood to build this bridge?
The mindless coding part starts one year later when you found that your mongoDB does not do joins, and you start implementing this as an extra layer in the client side.
Programming is thinking in the same exact way all knowledge work is thinking:
- Design in all it’s forms is mostly thinking
- Accounting is mostly thinking
- Management in general is mostly thinking
The meaningful difference is not the thinking, it’s what are you thinking about.
Your manager needs to “debug” people-problems, so they need lots of time with people (i.e. meetings).
You are debugging computer problems, so you need lots of time with your computer.
There’s an obvious tension there and none of the extremes work, you (and your manager) need to find a way to balance both of your workloads to minimize stepping on each others toes, just like with any other coworker.
I don't mean producing cryptic code-golf-style code, but the aspect that all the stuff you produce you have to maintain. This is certainly different from a novel author who doesn't care so much about maintenance and is probably more concerned about the emotions that his text is producing.
Best optimization is less interruptions as reasearch shows their devastating effect on programming:
- 10-15 min to resume work after an interruption
- A programmer is likely to get just one uninterrupted 2-hour session in a day
- Worst time to interrupt: during edits, searches & comprehension
I've been wondering if there's a way to track interruptions to showcase this.
Yet developers are expected to complete a few hours of coding task in between an endless barrage of meetings, quick and short pings & syncups over slack/zoom.
For the few times I've had to work on the weekends at home, I've observed that the difference in the quality of work done over a (distraction free) weekend is much better than that of a hectic weekday.
This is a great analogy I haven’t heard it before. They think it’s like that quick work where you check your calendar and throw in your two cents on an email chain. It’s not. Much more like holding a meeting.
If you want to tackle particularly hard problems and you get an interruption every 10 to 20 minutes you can just shelve the whole thing, because chances are you will just produce bullshit code that produces headache down the line.
We wrote a Windows front end and a Scala back end for data gathering and roled it out to a group of volunteers (including devs, lawyers and finace people even). Sadly the project ran out of time and budget just as things were getting interesting (after a first round of data analysis), so we never published a paper about it.
We also looked at existing tools such as Rescue Time ( https://www.rescuetime.com/ ) but decided an external cloud was not acceptable to store our internal productivity data.
I agree we can expand thinking to “thinking with help from tools”.
Programming is not about producing programs per se, it is about forming certain insights about affairs of the world, and eventually outputing code that is nothing more than a mere representation of the theory you have built.
I would say thinking about algorithms and data structures for algorithmic complexity not to explode.
>Nothing clever
A lot of devs use nested loops and List.remove()/indexOf() instead of maps, etc., the terrible performance gets accepted as the state of the art, and then you have to do complex workarounds not to call some treatments too often, etc., increasing the complexity.
Performance yields simplicity: a small increase in cleverness in some code can allow for a large reduction in complexity in all the code that uses it.
Whenever I do a library, I make it as fast as I can, for user code to be able to use it as carelessly as possible, and to avoid another library popping up when someone wants better performances.
Ironically enough it was nothing like what some architecture astronauts wring - just a set of simple to follow rules, like organizing files by domain, using immutable data structures and pure functions where reasonable etc.
Also I hadn't seen him use dependent types in the one project we worked together on and generics appeared only when it really made sense.
Apparently it boils down to using the right tools, not everything you've got at once.
OOP was a great concept initially. Somehow it got equated with the corporate driven insanity of attaching functions to data structures in arbitrary ways, and all the folly that follows. Because "objects" are easy to imagine and pure functions aren't? I don't know but I'd like to understand why corporations keep peddling programming paradigms that fundamentally detract from what computer science knows about managing complex distributed systems.
Yes, simple is good. Simple is not always easy though. A good goal to strive for nevertheless.
> nothing DRY
That's interesting. Would you prefer all the code to be repeated in multiple places?
Also, limit your abstractions’ external knowledge to zero.
> “I did this one thing here with data type A, and I’m doing something similar with data type B; let’s just create some abstraction for both of them!”
I'm guilty of this. I even fought hard against the people who wanted to keep the code duplicated for the different data types.
> “encapsulate behaviors that you need to synchronize.”
I like that!
If for instance you used a tree but were constantly looking up an index in the tree you likely needed a flat array instead. The most basic example of this is sorting, obviously but the same basic concepts apply to many many problems.
I think the issue that happens in modern times, specially in webdev, is we aren't actually solving problems. We are just glueing services together and marshalling data around which fundamentally doesn't need to be algorithmic... Most "coders" are glorified secretaries who now just automate what would have been done by a secretary before.
Call service A (database/ S3 etc), remove irrelevant data, send to service B, give feedback.
It's just significantly harder to do this in a computer than for a human to do it. For instance if I give you a list of names but some of them have letters swapped around you could likely easily see that and correct it. To do that "algorithmically" is likely impossible and hence ML and NLP became a thing. And data validation on user input.
So algorithmically in the modern sense is more, follow these steps exactly to produce this outcome and generating user flows where that is the only option.
Human do logic much much better than computers but I think the conclusion has become that the worst computer program is probably better at it that the average human. Just look at many niche products catered to X wealth group. I could have a cheap bank account and do exactly what is required by that bank account or I can pay a lot of money and have a private banker that I can call and they will interpret what I say into the actions that actually need to happen... I feel I am struggling to actually write what's in my mind but hopefully that gives you an idea...
To answer your nothing clever , well clever is relative. If I have some code which is effectively a array and an algorithm to remove index 'X' from it, would it be "clever" code to you if that array was labeled "Carousel" and I used the exact same generic algorithms to insert or remove elements from the carousel?
For most developers these days they expect to have a class of some sort with a .append and .remove function but why isn't it just an array of structs which use the exact same functions as every single other array... That people generally will complain that that code is "clever" but in reality it is really dumb. I can see it's clearly an array being operated on but OOP has caused brain rot and developers actually don't know what that means... Wait maybe that was OPs point... People no longer think algorithmically.
---
Machine learning, Natural Language Processing
This is true and is the cause of much frustration everywhere. Employers want “good” devs, so they do complicated interviews testing advanced coding ability. And then the actual workload is equal parts gluing CRUD components together, cosmetic changes to keep stakeholders happy, and standing round the water cooler raging at all the organisational things you can’t change.
It might be me not taking my time to learn Mathematica/Julia tho...
diagrams and this kind of planning is mostly a waste of time to be honest. You just need to start to work, and rework if necessary. This article is basically the peak of the bell curve meme. It's not 90% thinking, it's 10% thinking and 90% "just type".
Novelists for example know this very well. Beginners are always obsessed with intellectually planning out their book. The experienced writer will always tell you, stop yapping and start typing.
Relevant factors here are how cheaply you can detect failure (in terms of time, material, political capital, team morale) and how easily you can backtrack out of a bad design decision (in terms of political capital, how much other things need to be redone due to coupling, and other limitations).
The earlier you can detect bad decisions, and the easier you can revert them, the less planning you need. But sometimes those are difficult.
It also suggests that continuous validation and forward looking to detect bad decisions early can be warranted. Something which I myself need to get better at.
This is not true in general. Brandon Sanderson for example outlines extensively before writing: https://faq.brandonsanderson.com/knowledge-base/can-you-go-i...
And making changes on paper is cheaper than in code.
It still feels like you are coding so your brain is attached, but with rapid prototyping you are also designing, moving parts around to see where they would fit best.
Takes about 20 minutes to sharpen a chainsaw chain these days though...
Also, as someone famous once said: if I had 4 hours to sharpen an axe, I'd spend 2 hours preparing the whetstones.
LLMs can be cajoled into producing algorithms.
In fact this is the Chain-of-Thought optimisation.
LLMs give better results when asked for a series of steps to produce a result than when just asked for the result.
To ask if LLMs “think” is an open question and requires a definition of thinking :-)
But its an incomplete revolution. If you look at the UML diagram of a fully developed application its a mess of interlocked pieces.
Things get particularly hard to reason about when you add concurrency.
One could hypothesize that programming languages that "help thinking" are more productive / popular but not sure how one would test it.
There definitely are some jobs and some occasions where writing code is the dominant task, but in general the trend I've seen over the past 20 years I've been working has been more and more to "make these two things fit together properly" and "why aren't these two things fitting together properly?"
So in part I think we do a disservice to people entering this industry when we emphasize the "coding" or "programming" aspects in education and training. Programming language skills are great, but very important is systems design and integration skills.
“How long would it take you to type the 6 hours work of diff?” is a great question to force the cognitively lazy software manager to figure out how naive that is.
Nowadays I feel great when my PRs have more lines removed than added. And I really question if the added code was worth the added value if it’s the opposite.
Programming is mostly communicating.
That said, don't underestimate how much boilerplate code is produced. Yet another webshop, yet another forum, yet another customization of that ERP or CRM system. Crank it out, fast and cheap.
Maybe that's the difference between "coding" and "programming"?
I know I'm not alone in using these terms to distinguish between each mode of my own work. There is overlap, but coding is typing, remembering names, syntax, etc. whereas programming is design or "mostly thinking".
... and "whatever is left" is the thinking and planning side of things, which even in its diminished role in implementing a known solution, still comes into play every once in a while.
Other posters have it right I think. Fluency with the requisite domains greatly reduces the thinking time of programming.
Fluency increases the speed in which you move to other subjects but does not reduce your thinking, you're going to more complex issues more often.
Bug fixing is probably one of the best example: if you're already underwater you'll want to bandaid a solution. But the faster you can implement a fix the more you'll have leeway, and the more durable you'll try to make it, including trying to fix root causes, or prevent similar cases altogether.
One might say, "yes but if you see so many concurrency related bugs, what is the root cause and why don't you do that?" And sometimes the answer is just, "I work on a codebase that is 20 years old with hundreds of services and each one needs to have appropriate error handling on a case by case basis to suit the specific service so the root cause fix is going and doing that 100 times."
A good analogy that works for me is writing long form content. You need clear thought process and some idea of what you want to say, before you start writing. But then thinking also gets refined as you write. This stretches further: a English lit major who specialises as a writer (journalist?) writing about a topic with notes from a collection experts and a scientist writing a paper are two different activities. Most professional programming is of the former variety admitting templates / standardisation. The latter case requires a lot more thinking work on the material before it gets written down.
Walks, hikes and strolls are also a good techniques for figuring things out, famously preferred by philosophers like Kierkegaard and Nietzsche.
Sometimes I've brought it up with non-technical bosses how development is actually done, didn't work, they just dug in about monitoring and control and whatnot. Working remote is the way to go, if one can't find good management to sell to.
The diff will help, but it'll be an order of magnitude faster to do it the second time, diff provided or not.
For the same reason.
The rest of the time? Spent in two daily stand up meetings [1], each at least 40 minutes long (and just shy of half of them lasted longer than three hours).
I should also say the code base was C, C++ and Lua, and had nothing to do with the web.
[1] Because my new manager hated the one daily standup with other teams, so he insisted on just our team having one.
Of course, it will probably just devolve into a disengaged group of people that read emails or Slack in another window, so there's that.
[1] "Because I don't want them to be biased by knowing the implementation when testing" but in reality, quality went to hell.
But it seems this is only true for complete system designs from scratch after a first system has already been deployed, not for the small "deleted some code and now I'm rewriting it quickly" incidents (for which there is no special term yet?).
You'd do a fairly rough draft of the project first, just trying to make it do what you intend it to. Then you'd rewrite it so it works without glaring bugs or issues, then optimise it to make it better/more performant/more clearly organised after that.
Eg. https://realmensch.org/2017/08/25/the-parable-of-the-two-pro...
Earlier in my career I had a very intense, productive working day and then blundered a rebase command, deleting all my data.
Rewriting took only about 20 minutes.
However, like an idiot, I deleted it again, in the exact same way!
This time I had the muscle memory for which files to open and where to edit, and the whole diff took about 5 minutes to re-add.
On the way out to the car park it really made me pause to wonder what on earth I had been doing all day.
I also once butchered the result of 40 hours of work through a loose git history rewrite. I spent a good hour trying different recovery options (to no avail) and then 2 hours typing everything back in from memory. Maybe it turned out even better then before, because all kind of debugging clutter was removed.
The way I see it, programming is about “20% syntax and 80% wisdom”. At least as it stands today.
LLMs are good (perhaps even great) for the 20% that is syntax related but much less useful for the 80% that is wisdom related.
I can certainly see how those ratios might change over time as LLMs (or their progeny) get more and more capable. But for now, that ratio feels about right.
If I had my client report deleted today, I could rewrite that report in nearly half the time the next day because I remember the way in which I structured the report, the sentences that flowed that didn't and the way I conveyed the findings in a neutral way.
No different to designing a physical product. You might see the outcome, but you don't see the numerous design iterations and compromises that came along the way which speak to the design that came out the end.
Furthermore, there are going to be programmers that can write more code with less thought, because they might have many years of pre-thought knowledge and understanding that allows them to execute faster.
This article sounds like it was written for a manager that doesn't see the value in the work performed, or simply doesn't understand design related work.
Typing at an extra 15 wpm won't make a lick of difference in how quickly I produce a product, nor will how often my fingers leave the keyboard or how often I look at the screen. Once I've ingested the problem space and parameters, it all happens in my head.
The advantage of them is that my monitors and keyboards usually last a long time so putting money into them is not as wasteful as putting it into some other components.
One thing that surprised me though is that I recently bought a KVM to switch from desktop to laptop instead of a second monitor and this turned out to be both better and much cheaper. I gave away an older monitor to a relative and found that not having to turn to look at a 2nd monitor was actually nicer. Initially I really didn't want to do this and really wanted another screen but I had to admit afterwards that 1 screen + KVM was better for me.
RAM and disc space just matter up to the point of having enough so that I'm not wasting time trying to manage them to get work done.
It's the cheapest in their range, I think (about £30) - they have better ones.
Not massively flexible. Has a clicker switch which you could put on the floor if you wanted to let you flip displays. Not super fast at switching.....but it does the job for me. YMMV!
I use a 32-inch Viewsonic monitor with this. It's the most expensive monitor I've ever bought but it's nothing special when you look at what's out there. I't just lovely to use. :-) I think a purist would complain bitterly about refresh rates or whatever but I just love it and I spend my time reading web pages or code or watching the odd video.
When I'm writing something from scratch in a few months I can bash it all out on a small laptop - it is (as you say) all in my head, I just need to turn it into working code.
If I'm faced with some complicated debugging of a big existing system, or I've inherited someone elses project, that gets much easier with a couple of giant monitors to look at numerous files side by side - plus a beefier machine to reduce compile/run times as I'll need to do that every few mins.
You may care more about picking a keyboard & mouse/trackpad/trackball/etc if/when you start to experience pain in your wrists/hands and realise the potential impact on your career if it worsens! Similar situation with seating and back pain.
Typing out comments on PRs, reproducing issues, modifying existing code to test hypotheses, discussing engineering options with colleagues, finding edge cases, helping QA other tickets, and so on. I guess this is all "thinking," too, but it often involves a keyboard, typing, and other people
A lower but still significant portion is "overhead." Switching branches, syncing branches, rebasing changes, fixing merge conflicts, setting up feature flags, fixing CI workflows, and so on
Depending on the size of the team, my gut feel for time consumption is:
Communication > Thinking > Writing Code > Overhead
When you work for companies that take programming seriously (e.g., banks, governments, automotive, medical equipment, etc.), a huge development cycle occurs before a single line of code is written.
Here are some key development phases (not all companies use all of them):
1. high level definition, use cases, dependencies; traceability to customer needs; previous correction (aka failures!) alignment
2. key algorithms, state machines, flow charts (especially when modeling fail-safety in medical devices)
3. API, error handling, unit test plan, functional test plan, performance test plan
4. Alignment with compliance rules; attack modeling; environmental catastrophe and state actor planning (my experience with banks)
After all of this is reviewed and signed-off, THEN you start writing code.
This is what code development looks like when there are people's, business's, and government's lives/money/security on the line.
So. Much. Planning.
What you described is not how successful products are built and maintained; what you described is why we have world full of lots of shitty tech from “move fast and break things” ADHD-like management and young programmers that think they know everything and cry about having to do thinky work first. Literally the worst kind of programmers to have on a project.
I rewrite most of my code 2-3 times before I'm done and I'm still 5x faster than anyone else, and significantly higher quality and maintainability as well. People spend twice as long writing the ugliest, hackiest code as they would have to just learn to do it right
Not only does it take a week, but each attempt costs a few tens of thousands of dollars.
(Some) banks (sometimes) hire armies of juniors from Accenture. I wouldn't say they take programming seriously.
My government had some very botched attempts at creating computer systems. They're doing better these days, creating relatively simple systems. But I wouldn't say they're particularly excellent at programming.
Stubbing in a routine is fast, but then adding param checking, propagating errors, clean up, adding comments, refactoring sections of code into their own files as the code balloons, etc.
There's no thinking involved in most of the time I am coding. And thank god. If 11/12 of my time was spent twisting my brain into knots to understand the nuances of concurrency or thread-locking I would have lost my hair decades earlier.
In my experience, the main issue with learning to code are all the contexts you have to remember.
There is the static type level and the runtime level, all the scopes (class, object, function, nested functions, closures, etc.), the different machines (client, server, or even multiple servers, etc.)
That's probably the reason why most devs start with dynamic languages and frontend/mobile. It can get just as complex as backend development, but at least you can eliminate a bunch of contexts when starting to code, learn what's left and then add contexts later.
There is a reason why LISPers (I'm not one of them though) praise so much REPL-driven development: the REPL is a laboratory.
Also, how much time did you spend testing a library, looking on the internet how to install it, debugging the weird compiler errors? In the end you found the one option that made everything work but it took you hours of research and experimentation.
I was introduced to a quote from cartoonist, Guindon: "Writing is nature’s way of letting you know how sloppy your thinking is." From Leslie Lamport.
Although in my experience, thinking is something that is not always highly valued among programmers. There are plenty of Very Senior developers who will recommend, "just write the code and don't think about it too hard, you'll probably be wrong anyway." The whole, "working code over documentation and plans," part of the Agile Manifesto probably had an outsized influence on this line of reasoning. And honestly it's sometimes the best way to go: the task is trivial and too much thought would be wasted effort. By writing the code you will make clear the problem you're trying to solve.
The problem with this is when it becomes dogma. Humans have a tendency to avoid thinking. If there's a catchy maxim or a "rule" from authority that we can use to avoid thinking we'll tend to follow it. It becomes easy for a programmer to sink into this since we have to make so many decisions that we can become fatigued by the overwhelming number of them we have to make. Shortcuts are useful.
Add to this conflict the friction we have with capital owners and the managerial class. They have no idea how to value our work and manage what we do. Salaries are games of negotiation in much of the world. The interview process is... varied and largely ineffective. And unless you produce value you'll be pushed out. But what do they value? Money? Time? Correctness? Maintainability?
And then there's my own bone to pick with the industry. We gather requirements and we write specifications... some times. And what do we get when we ask to see the specifications? A bunch of prose text and some arrows and boxes? Sure, some one spent a lot of time thinking about those arrows and boxes but they've used very little rigor. Imagine applying to build a sky scraper and instead of handing in a blueprint you give someone a sketch you drew in an afternoon. That works for building sheds but we do this and expect to build sky scrapers! The software industry is largely allergic to formalism and rigor.
So... while I agree, I think the amount of thinking that goes into it varies quite a lot based on what you're doing. 11/12? Maybe for some projects. Sometimes it's 1/2. Sometimes less.
It wasn't even the worst code base I've inherited but it is the worst lines of code per hours worked I've ever had.
So thinking does not merely make you a better programmer. It makes you a better programmer at every given time . Your progression never stops and like I just said, it's simply called learning.
I think they are in an indirect way. Being able to touch type reasonably fast prevents the action of typing distracting you from your thoughts, or lagging so far behind your thoughts that it makes it harder to keep your thoughts clear in your mind.
Maybe something similar with good tools.
The title, read alone, with only a brief skim of the article might give PHBs the notion that you can just sit developers in a room and let them “think” for 5.5 hours and the hand them their keyboards for the last 30 minutes and get the product you want.
This is how I know it's a work of fiction. Sadly, even these days daily backups in most organizations, even IT ones are an impossible dream.
Programming has both analytical and creative part, which should be balanced. If you are over-analytical you don't get stuff done quickly.
I accidently deleted about 2 weeks of my work once. I was a junior dev and didn't really understood how svn works :). It took about 2 days to finish the job, but I had no diff and it wasn't 100% ready, so after recreating what I had I still had to spend about a day to finish it.
TL;DR: I think 11/12th is a reasonable estimate.
Copilot is above all fantastic for outputting routine tasks and boilerplate. If you can, through the power of thinking, transform your problem into a sequence of such well-formed already-solved tasks, it can basically be convinced to do all the key-pressing for you.
An iterative model which has been up-front loaded with a firm architecture, feature elaboration, a rough development and testing plan, resources allocated and some basic milestones to hit so that upper mgmt. can get an idea when useful stuff might land.
The development _process_ can be as agile-y as you like, so long as the development of features moves incrementally with each iteration towards the desired end-goal.
But you have to be strict about scope.
"Programming Is Mostly"
(1) making sense out of missing or, as technical writing, badly written documentation
needed to do the
(2) mud wrestling of system management.
Example 1: Had everything else working then needed a connection string or some such between my Visual Basic .NET code and SQL Server. Struggled with (1) and (2) full time for over a week, with frustration rising like a South Pacific volcano getting ready to erupt, finally reached by phone some relatively high executive who was surprised that anything so routine could be so difficult and quickly gave me the secret. Then my work raced ahead, no problems, and all my code worked fine.
Example 2: Wanted a way for occasional, simple, routine file copying between two computers on a LAN (local area network) from both being connected to the same cable modem. Looked at the old "NET SHARE" and "NET USE", encountered mostly unclear, obscure, undefined technical terminology, tried to make sense out of the obscure syntax diagrams, observed that apparently nearly none of the many combinations of claimed options actually worked, and eventually, from two weeks of full time work, like throwing mud against a wall to see what would stick, underhand, back spin, side arm, etc., did a lot of guessing about what could be wrong and why (mostly involving computer security), discovered that likely computer A might be able to initiate a read from computer B but no way could computer B initiate a write to computer A, etc., got somethings working, but still need to document the effort.
More problems on the horizon ahead:
Problem 1: How to have on one computer at least two instances of the operating system on separate (bootable) hard disks and be able routinely (a) to back-up to additional internal and/or external hard disks all of the installed instances or restore from those backups and (b) recover quickly in case any hard disk fails or any bootable instance becomes corrupted.
Problem 2: How to install PostGreSQL on Windows 7 Professional and/or Windows Server 2019 and get code in Visual Basic .NET to use PostGreSQL. Is there some good documentation?????? Will be thrilled to learn that in this case there is no problem!!!
Once (1) and (2) are out of the way and, as results, the basic tools are working, the APIs (application programming interfaces) are well documented, then the syntax and semantics of the programming languages are easy and the programming itself is the easy, short, sweet dessert after all the nonsense before. The heap data structure, B+-trees, key-value stores, the .NET platform invoke, matrix inversion and eigenvalues, the Gleason bound, .NET managed memory, semiphores for controlling multiple threads, base64 encoding, HTML, etc. -- all really simple, fast, easy. (1) and (2) -- well over 70% of the effort.
Sadly, after all these years programming, I have yet to discern any real vulnerability in the US government.
Compare the sorts of teams that do prototyping and the sorts of teams that work to a Gantt chart.
* the ideal light cav trooper was jockey-sized, highly observant, and was already a good horseman before enlisting; the ideal heavy cav trooper was imposing, obedient, and was taught just enough horsemanship to carry out orders but not so much that he could go AWOL.
You could see the recon as the thinking from the article. The enemy and terrain are the code and various risks and effects associated with changing it.
Also, very very rarely is someone just sitting around and pondering the best solution. It happens, and yes it's necessary, but that's forgetting that for so much work the solution is already there, because one has already solved it a thousand times!
This article is straight gibberish except for perhaps a small corner of the industry, or beginners.
I have been in this career for 20 years, I'm running my solo company now, and I'd say I spend on average 2 hours coding a day. I spent 10 hours a day just thinking, strategizing, but also planning major features and how to implement them efficiently. Every time I sit down to code something without having planned it, played with it or left it to simmer in my subconscious for a couple days, I over-engineer or spend time trying an incorrect approach that I will have to delete and start again. When I was an employee, the best code was created when I was allowed to take a notepad, a cup of coffee and play with a problem away from my desk, for however long I needed.
One hour of thinking is worth ten hours of terrible code.
---
1: If our programming languages were better, I would do the same. But apart from niche languages like Lisp, modern languages are not made for exploratory programming, where you play and peel a problem like an onion, in a live and persistent environment. So planning and thinking are very important simply because our modern approach to computing is suboptimal and unrefined.
Writing (code) is thinking.