Rolled my eyes on "For experts only: don't do it yet". Shut-up already. I will do it right now because it will nag me forever and then surface will grow, and every time the new code interacts whith what-could-ve-been-optimized I will spend 5min thinking if I should already optimize it
There's so much good advice in this article. My number one point that i learned the hard way during two decades of writing software: take breaks when your body tells you to. It's an absolute killer if you force yourself to work on your projects just because there's stuff on your to do list, new issues on Github, or whatever. Just stop working if you don't feel it.
But this one in particular stands out. We are being constantly pushed to ship code at faster and faster rates. AI has only hastened the process.
If you want to learn anything new you have to slow it down, push back against all the forces urging you to do more, ship more, make more money.
If you're using AI tools, do the opposite of what everyone else is doing. For every piece of generated code you accept, scrutinize every line, ask clarifying questions, ask for alternate implementations, ask what the tradeoffs are.
I think a lot of this is addressed by having a definition of done and more generally being explicit about quality expectations. You don't need to worry whether to polish the readme or add cross-compilation if you conscious about your quality expectations and the drivers behind them - there is no single 'best' project.
I find it efficacious to have an integrated product going as soon as possible, even if it’s a field of stubs.
It’s my experience that I almost never know what the end product will look like, no matter how much upfront planning time I devote, so being able to test and iterate the whole system, as soon as possible, is pretty vital.
It’s also one reason that I like to use test harnesses a lot[0].
You struggle with a feature or a bug, you think about it, you weigh the pros and cons for hours... because you don't want to start something that will set you back. You're tired, but you don't want to go to sleep until you've at least made a decision for tomorrow.
Go to sleep. Now.
Then you wake up knowing immediately what to do. You hardly believe it, because it was so hard to find before you sleep. And you do it. And it works. And you know that sleep was the key.
I hate to turn everything into a conversation about AI, but this essay maybe explains best what LLMs have done for me recently.
Particularly the first part. I want to add a new feature, but I want to keep things clean. It needs tests, CI, documentation.
It makes exploring new ideas a bit cumbersome, because code tends to create minor distractions that eat up time. You miss a semicolon, or you forget the order of the arguments to a function you just wrote, do you have to flip to another file. Or the test framework needs an update, but the update breaks something so you have to do some changes. It's not just the time either, it's the context switch from the big picture to the very small details, and then back again.
LLM lets me do "one whole step" at a time. Or that's the positive spin on it. Seen another way, I'm further out from the details, and in most things, you have to hit a bit of a wall to really learn it. For senior devs, I lean towards the first, you've already learned what you're going to learn from fixing imports, you are operating on a higher level.
When faced with a big task and not knowing where and how to start, a trick I like is writing something crappy that is roughly a step in the right direction. For example, if you're building a web browser (huge monumental task), just load a page with your favorite http lib and display it, html tags and all. You know that none of that code will survive, but it's something that you can build on, and in due time you'll come around and replace it with the right design.
I can feel this block, especially when I'm starting a new project.
Two things that help me:
* have a good boilerplate
* ship things that do nothing
i.e. I find it helps to start a project using my good boilerplate then set up builds and releases (so for web projects, put them online) so that the page doesn't look so blank anymore, and I can see my progress in "releases" even if they're just for me/others contributing.
> A new project and it’s going to be your best ever
A good defense against this is borrowing stuff from your prior projects, alongside eventually creating templates for the most common stuff.
For example, in new side projects I start, I can borrow the web server (ingress) configuration from the prior ones, same for CI pipelines and a large part of the previous Dockerfiles, sometimes even entire services with all of the annoying setup and configuration stuff already done.
Plus, this way, you have a more or less working baseline and further iteration is entirely up to you - and if you do want to improve things a bunch, then the next time your template will be even better and you'll be able to backport whatever you think everything should have to your other projects as well.
Going with the simplest solutions along the way helps: Bash scripts for triggering builds, CI configuration just calling those, using Docker or similar containers for the environments and builds, your ingress just being Nginx/Caddy/Apache2/..., using PostgreSQL or SQLite and specialized stuff like Redis/Valkey, RabbitMQ, MinIO and so on instead of reinventing the wheel.
Sometimes it's also useful to write utility scripts and even small tools to help with the projects, I bet developers that have been around for decades and are way better than I am have a lot of that stuff, alongside a healthy helping of dotfiles for existing tools to get in the zone while doing the dev work. Although it can also be helpful to go the YAGNI route and customize things as little as possible, like a stock IDE install, not even bothering with the color themes or keybinds or a plethora of plugins - just install and go.
If I’ve had a break, gone for a walk, left it overnight, worked on something else simple for a bit and tried the other usual ‘fixes’ and am still stuck then I find ‘just do it’ really helps me. I find if I just write some code even slightly related to the goal, even if it’s complete garbage that gets deleted later, then I get unstuck. Although unfortunately even getting to that point takes a couple of days sometimes. We can’t always perform immediately on demand.
Perhaps switch languages/paradigms for a few days. If you are used to using "text-based" languages such as golang, python, c++ or java, try something like Smalltalk to freshen you up. Pharo https://pharo.org/ is a nice implementation.
Besides mentioned by others walks and sleep I found meditation to be really helpful; you often can get the benefits, ideas-generation-wise, of a full-night sleep doing solid 30-minute session. There are other benefits of meditating too :)
I second doing intermittent chores, but rather the literal actual household chores, helps you to relax while being productive and putting your mind at ease from the main task you are focusing on otherwise.
For solo work, I've found a framework of four learning modes effective: reading, when you are exploring something new, sketching/speccing depending on the detail level you're aiming for, coding only when you might forget things you didn't bother writing down, and relaxing as the fallback state. The key is to be in only one mode at a time and to avoid getting stuck in any single one. Based on nature of the work, you might switch two or three times a day. And always know the next two immediate steps; if you don't, that's your signal to switch. Rinse and repeat.
I suffer from this. I even get as far as nearly finishing a project, and then just decide to abandon it as the last 20% is just mentally exhausting, and I should have written the whole thing in language X using framework Y…
> You may be held up by a problem in a dependency such as poor documentation. It is tempting to start filling in the missing docs, but try to resist that temptation. Better to make minimal personal notes for now and, after you’ve made good progress, considering scheduling time to contribute some docs to the dependency.
I agree with most of the article, but this part keeps me thinking. Scheduling to contribute later will almost never work. Either I do it now or never. The task is lost in a list of infinitely many tasks. Also, contributing to a dependency (if I understand this correctly) is always something that helps at least two: yourself - doing something good, helping to improve someone’s work, getting something done - and the person who works on the dependency project. The other gets (positive) feedback and knows someone uses their product/software/library
Naming was often my biggest block. I often know the project topic, but cannot choose a name. Then, of course, there's variable, function and file naming. Turns out the AI is fantastic at choosing good names, so that block is largely obviated these days.
31 comments
[ 3.0 ms ] story [ 56.5 ms ] thread> Take time with learning
But this one in particular stands out. We are being constantly pushed to ship code at faster and faster rates. AI has only hastened the process.
If you want to learn anything new you have to slow it down, push back against all the forces urging you to do more, ship more, make more money.
If you're using AI tools, do the opposite of what everyone else is doing. For every piece of generated code you accept, scrutinize every line, ask clarifying questions, ask for alternate implementations, ask what the tradeoffs are.
Just be curious.
This will be slow, but that's the point.
I’m big on this.
I find it efficacious to have an integrated product going as soon as possible, even if it’s a field of stubs.
It’s my experience that I almost never know what the end product will look like, no matter how much upfront planning time I devote, so being able to test and iterate the whole system, as soon as possible, is pretty vital.
It’s also one reason that I like to use test harnesses a lot[0].
[0] https://littlegreenviper.com/testing-harness-vs-unit/
How many times has this happened to me?
You struggle with a feature or a bug, you think about it, you weigh the pros and cons for hours... because you don't want to start something that will set you back. You're tired, but you don't want to go to sleep until you've at least made a decision for tomorrow.
Go to sleep. Now.
Then you wake up knowing immediately what to do. You hardly believe it, because it was so hard to find before you sleep. And you do it. And it works. And you know that sleep was the key.
Particularly the first part. I want to add a new feature, but I want to keep things clean. It needs tests, CI, documentation.
It makes exploring new ideas a bit cumbersome, because code tends to create minor distractions that eat up time. You miss a semicolon, or you forget the order of the arguments to a function you just wrote, do you have to flip to another file. Or the test framework needs an update, but the update breaks something so you have to do some changes. It's not just the time either, it's the context switch from the big picture to the very small details, and then back again.
LLM lets me do "one whole step" at a time. Or that's the positive spin on it. Seen another way, I'm further out from the details, and in most things, you have to hit a bit of a wall to really learn it. For senior devs, I lean towards the first, you've already learned what you're going to learn from fixing imports, you are operating on a higher level.
I start to experiment with coding agents to try some things to make me unstuck. These are cheap to try.
Then, the outcome is either "wow, this can actually work" or "but this is bullshit, and will never work, let me do it myself the right way!"
Win/win.
It had some good stuff in it, the best of which (for me) was: when stuck, write debugging infrastructure.
[1] https://oxide-and-friends.transistor.fm
[2] https://oxide-and-friends.transistor.fm/episodes/coders-bloc...
Edit: punctuation
Two things that help me:
* have a good boilerplate
* ship things that do nothing
i.e. I find it helps to start a project using my good boilerplate then set up builds and releases (so for web projects, put them online) so that the page doesn't look so blank anymore, and I can see my progress in "releases" even if they're just for me/others contributing.
Simplify the mental model of the code, product, etc. Discuss it with someone.
A good defense against this is borrowing stuff from your prior projects, alongside eventually creating templates for the most common stuff.
For example, in new side projects I start, I can borrow the web server (ingress) configuration from the prior ones, same for CI pipelines and a large part of the previous Dockerfiles, sometimes even entire services with all of the annoying setup and configuration stuff already done.
Plus, this way, you have a more or less working baseline and further iteration is entirely up to you - and if you do want to improve things a bunch, then the next time your template will be even better and you'll be able to backport whatever you think everything should have to your other projects as well.
Going with the simplest solutions along the way helps: Bash scripts for triggering builds, CI configuration just calling those, using Docker or similar containers for the environments and builds, your ingress just being Nginx/Caddy/Apache2/..., using PostgreSQL or SQLite and specialized stuff like Redis/Valkey, RabbitMQ, MinIO and so on instead of reinventing the wheel.
Sometimes it's also useful to write utility scripts and even small tools to help with the projects, I bet developers that have been around for decades and are way better than I am have a lot of that stuff, alongside a healthy helping of dotfiles for existing tools to get in the zone while doing the dev work. Although it can also be helpful to go the YAGNI route and customize things as little as possible, like a stock IDE install, not even bothering with the color themes or keybinds or a plethora of plugins - just install and go.
For solo work, I've found a framework of four learning modes effective: reading, when you are exploring something new, sketching/speccing depending on the detail level you're aiming for, coding only when you might forget things you didn't bother writing down, and relaxing as the fallback state. The key is to be in only one mode at a time and to avoid getting stuck in any single one. Based on nature of the work, you might switch two or three times a day. And always know the next two immediate steps; if you don't, that's your signal to switch. Rinse and repeat.
I agree with most of the article, but this part keeps me thinking. Scheduling to contribute later will almost never work. Either I do it now or never. The task is lost in a list of infinitely many tasks. Also, contributing to a dependency (if I understand this correctly) is always something that helps at least two: yourself - doing something good, helping to improve someone’s work, getting something done - and the person who works on the dependency project. The other gets (positive) feedback and knows someone uses their product/software/library