I find it best to read documentation and seek out good textbooks. This can be tiring, but the trick is to put zero pressure on remembering or understanding anything - there's no exam!
Lazily scanning through every function in a library / scale in a musical style / brush type in an art catalogue e.t.c. will go a looong way! You will be amazed at how much you recall when you get stuck.
For coders, I recommend learning some C (don't worry, it's small!) and doing an embedded software project (I highly recommend the Raspberry Pi Pico!). Much of modern programming practice is arguably a reaction to the decades spent doing similar tasks with low level languages and low-power hardware. Experiencing this really helps to contextualise things. I guarantee you won't look at your laptop / phone / washing machine the same way again :)
Some of my favourite and most rewarding tool choices have been in direct defiance of my prejudices. In fact, nowadays I actively recommend trying something utterly bizarre (like vim) on the off chance you fall in love (like I did, with vim).
Enjoying a tool is important. If you find that you do, use that energy to learn it inside-out!
Honestly, thinking about recommendations with hindsight is tricky. Much of what I have learned was motivated by aspirations that have long since changed.
If I met my past self... I doubt I could convince them to relax, ignore what's trendy, and do more aimless studying!
TL;DR: just focus on changing your perspective, you will gain confidence over time :)
For specific more suggestions, check out my links & books page.
I also have a fine art learning adventures page.
My main machine is a Framework laptop. I love it.
I used to buy relatively cheap gaming laptops, but I often found myself disabling the discrete GPUs to prevent excess heat and power consumption.
I hope to keep my Framework for as long as possible, perhaps upgrading to a RISC-V CPU years from now.
I have a Pinebook Pro. It's really nice to use. If I only did systems programming, I would probably make this my main laptop.
I use an ErgoDox EZ for typing. I like the keyboards on my laptops, but the EZ helps with my RSI.
It also encouraged me to improve my touch-typing, and use a more code-friendly symbol layout. I bought the blank key caps and labelled them with marker pens.
I have a small Wacom Intuos tablet, which I use for digital modelling / painting. Blender is really powerful with a 3-button mouse, and my stylus has two thumb buttons which are great for RMB / MMB mapping.
My phone is a Fairphone 3 running iodéOS. I mainly use it for instant messaging, 2FA, or listening to music. I love what Fairphone are doing, but I hope to ditch Android someday for a more flexible mobile OS. The Pinephone Pro looks promising.
I love using Raspberry Pis for things. I have a Pi 3+ with a DAC board running Pianoteq. It can turn any midi keyboard into a great sounding piano!
For photos, I either use my phone, or an Olympus OM-10 35mm film camera.
For videos, I use an old Canon EOS M with a cheap CCTV camera lens, running Magic Lantern. I used to use a 550D (Rebel T2i in the US), but the EOS M offers similar quality and is much smaller and cheaper.
Oscilloscopes are wonderful. I primarily use one for making audio electronics, which has relatively low frequency requirements. Two channels is nice, but not required.
Make sure you understand how to not blow up your scope!
Most analogue audio projects require bipolar ±12v power! It's safest to set this up so that 0v is tied to earth ground, but this requires a dual output supply which can handle negative voltage.
Moritz Klein has a tutorial on creating a simple synth power supply. This is great for powering finished projects, but a proper lab bench power supply provides desirable prototyping features, such as short-circuit protection.
I use the Hakko FX-888D soldering station. Soldering is deceptively difficult, especially without enough heat.
I have to use all sorts of applications & operating systems for my work... I like learning new things, but I rarely enjoy them beyond that!
Blender, Krita, Firefox, and KiCAD are generally the only GUI apps I keep installed. I love Houdini too though.
My personal laptop runs Ubuntu, as it stays out of my way more than Windows / macOS. I like to treat devices as being separate from my tasks & data, so anything with sensible defaults is great. I use the fish shell for this reason to.
Most of my personal stuff is done via command line interfaces, simple shell scripts, PGP encryption, and tabulated plain-text files. My growing collection of DIY tools has yet to fail me... although there were some nasty data losses while I was learning - backup your backups!
I use RSS feeds to keep up to date with blogs, youtube, tweets e.t.c.
If you are looking to pay me for client work but have lost my invoice, or would like to reimburse me for something, please email me.
If you want to support what I do, thanks :) I don't accept donations, but I would love it if you donated to Abortion Rights UK, Mermaids UK, or Gendered Intelligence.
I've found that, with a consistent strategy, memory management is actually super simple!
When working with modern amounts of RAM, we can comfortably request a large chunk of memory up-front. In fact, I like to get memory up-front as much as possible, as negotiation with the OS (through malloc, VirtualAlloc, or mmap) has an unpredictable duration and could just fail.
But once we control a chunk of memory, how should it be managed?
We could use it as an array, keeping track of offsets and data layouts, but this would be a pretty complex system.
Sometimes such complexity is necessary, but for something as universal to coding as just data being in memory, this is a waste of head space.
I use an 'allocator' object. It manages memory internally as a stack, and uses assertions to enforce limits and check for bugs. Multiple allocators can be used (or even nested!) to represent abstract ideas. However, the trick to keeping functions simple and generic is to limit them to one allocator parameter as often as possible.
But what if a function internally allocated stuff for its own intermediary data. Should this now-redundant data stick around, wasting space in the allocator's memory?
We can simply copy data we want to keep to a different allocator, then release the redundant allocation.
data = load_file(alloc_temp, file_path);
The vast majority of allocations are temporary, with occasional copying of persistent data. I'm mostly writing software with a concept of frames, so I like to use a temporary allocator which gets freed at the start of each new frame, along with persistent ones representing loaded resources, cached calculations, e.t.c.
Check out my implementation of pf_alloc to see this stuff in practice.