Being productive with your tools

Mag­num is de­veloped with a “Zen Garden” philo­sophy in mind, fo­cus­ing on pro­ductiv­ity, pre­dict­ab­il­ity and ease of use. Let’s see how that can ex­tend bey­ond just the lib­rary it­self — in­to your daily work­flow.

Triggered by an (ad­mit­tedly very harsh) re­cent art­icle by @cliff­ski, a re­cent need to re­boot in­to Win­dows 10 in or­der to fix MS­VC 2019 sup­port in Mag­num (to be hor­ri­fied from the UX of Win­dows 10), and a res­ult­ing dis­cus­sion on our Git­ter chat, I de­cided to share what I think is use­ful for be­ing a pro­duct­ive de­veloper. In this case with Linux and the KDE Plasma 5 desktop be­ing my sys­tem of choice.

Git is a friend, not a des­pised en­emy

Think of Git not as of the an­noy­ing ob­scure last-mile tool to “push your code to cus­tom­ers”, but a tool that can act­ively keep you fo­cused, or­gan­ized, help you re­view your changes, have your edit his­tory safe and let you eas­ily pick up in­ter­rup­ted work from yes­ter­day.

I’m reg­u­larly us­ing git status and git diff as a “scope guard” — to avoid the set of changes in my work­ing copy grow­ing too large. Then I’m us­ing the in­ter­act­ive git add -i to pick rel­ev­ant changes and com­mit them in­to as many sep­ar­ate com­mits as de­sir­able, of­ten us­ing git re­base -i to back-in­teg­rate fixup patches to ex­ist­ing com­mits.

There’s noth­ing easi­er than do­ing a quick git stash to see if your latest modi­fic­a­tions are to blame for broken tests or if it’s some­thing else.

Some people ar­gue that “[their] job is cod­ing, not mak­ing beau­ti­ful com­mit logs”, but from my ex­per­i­ence scop­ing up a task in­to a se­quence of clean com­mits helps a lot — if the diff is self-con­tained, makes sense and doesn’t con­tain un­re­lated changes, you can re­view your work much easi­er and be sure you didn’t mess any­thing up. It pays off later when in­vest­ig­at­ing bugs as well, git blame to­geth­er with git bisect are power­ful tools for pin­ning down is­sues in large or un­fa­mil­i­ar code­bases. But they need a clean his­tory to work prop­erly.

Get to know your ed­it­or, shell and key­board lay­out

While every ed­it­or is dif­fer­ent, there are a few fea­tures I ab­so­lutely de­mand to con­sider it us­able. If the ed­it­or starts slow, has a typ­ing lag, can’t ap­ply a con­sist­ent in­dent­a­tion and whitespace policy, doesn’t know block edit­ing or com­ment­ing/un­com­ment­ing code isn’t a key short­cut, then it’s use­less for me. Kate from KDE (and everything based on it — KWrite, KDevel­op) is my ed­it­or of choice. I have to ad­mit I nev­er bothered to learn Vim — mostly be­cause the cur­rent way I edit files is fast enough, the bot­tle­neck be­ing my brain and not “how fast I can type”.

Know­ing how to nav­ig­ate with key­board is es­sen­tial as well — far too of­ten I see seni­or pro­gram­mers with 20+ years of ex­per­i­ence mov­ing across words or lines only by re­peatedly press­ing ar­row keys like if there was no oth­er way. Ctrl Ar­row skips whole words and there’s Home / End, use them! On Mac, how­ever, I was nev­er able to have those work con­sist­ently across apps and it’s one of reas­ons why I’d rather SSH in­to a Mac than use its key­board dir­ectly.

Pick a shell where you can work fast — 90% of what you do there is re­peatedly ex­ecut­ing short com­mands, so it’s es­sen­tial to have this op­tim­ized. The plain Win­dows cmd.exe is ab­so­lutely ter­rible at that, but most oth­er shells can be made a joy to work with if you con­fig­ure their his­tory hand­ling. If you are on Win­dows and can’t or don’t want to use Git Bash (which con­tains readline and thus can be made us­able), have a look at Clink.

"\e[A":history-search-backward
"\e[B":history-search-forward

Paste this in­to your /etc/inputrc, open a new ter­min­al, type a com­mand pre­fix and pres Up to auto­com­plete it from typed his­tory. Simple and in­tu­it­ive. You can thank me later.

Have your desktop work for you

I have a single ex­tern­al 27” 4K screen. It prac­tic­ally cov­ers my field of view and fits everything I can fo­cus on in a single mo­ment, but not more. By choice — I cur­rently don’t have any de­sire to use more than one screen. What I usu­ally see else­where is people hav­ing one screen with an IDE and the oth­er with a single Slack win­dow, an e-mail or a browser, with all the mes­sages, an­im­ated ads and no­ti­fic­a­tions con­stantly beg­ging for at­ten­tion, only mak­ing fo­cused work miser­able.

What I have in­stead is six vir­tu­al desktops — one ded­ic­ated for the browser, an­oth­er three for work, one desktop solely for file / pack­age man­age­ment and one with a mu­sic play­er. This makes it pos­sible to have each vir­tu­al desktop a single area of fo­cus, com­pared to a pile of win­dows the IDE won’t dis­tract you when read­ing a PDF and a browser win­dow won’t dis­tract from cod­ing. It’s im­port­ant that the taskbar shows only win­dows from the cur­rent desktop and noth­ing else. Re­cently I even turned off all browser push no­ti­fic­a­tions so activ­ity from one vir­tu­al desktop doesn’t leak in­to oth­ers in any way.

Desktop switch­er in the taskbar
Ctrl F1F6 short­cuts for switch­ing. Ctrl F1 is al­ways the browser desktop.

Im­port­ant for desktop switch­ing short­cuts is that they’re ab­so­lute (so I don’t have to think about dir­ec­tion, just the des­tin­a­tion) and that there’s no an­im­a­tion — if the brain is fo­cused on a par­tic­u­lar screen area, quick switch­ing to an­oth­er desktop and back will not cause it to lose con­text. That’s also why I nev­er use Alt Tab, it has an un­pre­dict­able or­der and causes so much visu­al noise that los­ing con­text is in­ev­it­able. An­oth­er es­sen­tial fea­ture is an abil­ity to make a win­dow stay al­ways on top or be present on all vir­tu­al desktops — a float­ing con­sole win­dow with a long-run­ning op­er­a­tion, for ex­ample.

Al­ways on top
A diff opened in gitk stays on top while edit­ing code in a full­screen IDE be­low; a “rolled-up” con­sole win­dow with a long-run­ning op­er­a­tion above it.

Your com­puter can be a power-house

It’s com­mon for me to have a browser with 100+ tabs open, two IDEs with ~50 files each, sev­er­al con­sole win­dows each with mul­tiple tabs, file man­ager with five split tabs, a dozen of PD­Fs open on top and a spread­sheet for pro­cras­tin­at­ing on my taxes. When I fin­ish my work, I put the laptop to sleep and when I re­sume work the next day, it’s all there, ex­actly how I left it. Up­time of 90 days isn’t any­thing ex­traordin­ary either.

A laptop with 16 GB of RAM, of­ten run­ning only at 800 MHz, has no prob­lem keep­ing up with all that. But it’s im­port­ant that I can rely on the sys­tem to not do any shady busi­ness in the back­ground — hog­ging the CPU with an an­ti­vir­us check or down­load­ing giga­bytes of sys­tem up­dates un­less I tell it to (and then ran­domly re­boot­ing) would be an ab­so­lute showstop­per.

Little Big Things

On KDE Plasma, if I press Alt F2, KRun­ner, a popup search win­dow, ap­pears. It can open apps, search tabs in my browser, do simple cal­cu­la­tions but also has a plu­gin that gives me ac­cess to a data­base of pre-defined sym­bols — wheth­er I need an em-dash for a tweet, a trade­mark char­ac­ter or a ¯\_(ツ)_/¯ re­sponse for a chat. A crit­ic­al re­quire­ment is that it has to work pre­dict­ably and without any delay; typ­ing a known pre­fix and press­ing Enter will al­ways give the same res­ult, no mat­ter how fast I type.

An­oth­er very handy thing is a glob­al key­board his­tory. More of­ten than not, you need to copy sev­er­al things at once, not just one. Or you ac­ci­dent­ally copy some­thing and lose the pre­cious clip­board con­tents. Es­pe­cially when you need to switch win­dows or desktops to copy mul­tiple things, the visu­al noise will make your brain go out of the zone very quickly. With Klip­per I can use Ctrl Alt Up or Down to pick a dif­fer­ent entry from the clip­board his­tory.

Py­thon is the best cal­cu­lat­or, shell and knife

It’s a good idea to have a pen and a piece of pa­per on your desk, es­pe­cially when you are cod­ing visu­al things. Us­ing it to cal­cu­late a dot product by hand isn’t. A ter­min­al win­dow with an in­ter­act­ive Py­thon in­stance is a much bet­ter tool. And with Mag­num now get­ting Py­thon bind­ings, it has everything needed.

>>> from magnum import *
>>> Matrix3.rotation(Deg(45))
Matrix(0.707107, -0.707107, 0,
       0.707107, 0.707107, 0,
       0, 0, 1)

Quick, where are the minus signs in a 2D ro­ta­tion mat­rix?

Py­thon is the go-to choice also for all string-pro­cessing shell scripts longer than one line — in­stead of try­ing to re­mem­ber how to use awk and cut in­side a while loop in Bash, whip that up in Py­thon. It’ll be easi­er to de­bug, ex­tend and you wouldn’t need to learn the ob­scure tools again a week later.

Fast it­er­a­tion times are key

There’s no worse pro­ductiv­ity killer than a tool that makes me wait un­til an op­er­a­tion is done. That’s a forced in­ter­rup­tion and my brain im­me­di­ately gives up on all con­text. I can it­er­ate or core APIs in Mag­num ba­sic­ally without in­ter­rup­tion, in­cre­ment­al com­pil­a­tion tak­ing few seconds at most. Then, with Util­ity::Tweak­able, I can live-edit con­stants in a run­ning app for even faster turn­around times.

In con­trast, Mag­num’s Py­thon bind­ings are done with py­bind11, which ex­poses a very simple API do­ing very com­plex things un­der­neath. How­ever I soon got in­to a state where the it­er­a­tion time of a single com­pile & link got to al­most a minute — the whole en­gine with 800 tar­gets com­piles from scratch faster than that. To stay oc­cu­pied dur­ing this “down­time”, I tem­por­ar­ily switch to an­oth­er task, but the con­text switch over­head slowly makes the fo­cus dis­ap­pear.

Have a stack you can trust …

With Mag­num not far from be­ing a dec­ade old, I have the lux­ury of re­ly­ing on a ma­ture, stable and well-tested code­base. De­vel­op­ing new things on top of a trus­ted stack is a breeze, be­cause com­bin­ing well-tested and well-un­der­stood build­ing blocks most of­ten leads to the res­ult be­hav­ing cor­rectly as well — with any de­bug­ging hap­pen­ing only on the sur­face level.

This ex­tends to provid­ing sup­port as well — know­ing the in­tern­als well I can quickly nar­row down a re­por­ted prob­lem, re­motely dia­gnose it by ask­ing just a few ques­tions and provide either a solu­tion or a work­around al­most im­me­di­ately.

… and sev­er­al al­tern­at­ives for the stacks you can’t

Not everything is a “Zen Garden”, though — there’s the OS, GPU drivers, third party lib­rar­ies, com­pilers and hard­ware, each at a vari­ous state of sta­bil­ity. For those it’s im­port­ant to al­ways have an al­tern­at­ive im­ple­ment­a­tion to test on — if an im­age fails to load with one plu­gin, try with an­oth­er. If a shader works flaw­lessly on one GPU, it might as well crash and burn on an­oth­er.

Try to primar­ily de­vel­op against the most con­form­ing im­ple­ment­a­tion (of a com­piler, stand­ard lib­rary, GPU driver, file format load­er) and reg­u­larly test on at least one oth­er, to veri­fy your as­sump­tions. In­vest­ing a week (or even a month) of your time in­to set­ting up a CI test mat­rix that does auto­mat­ic test­ing for you on sev­er­al dif­fer­ent plat­forms, ideally in­clud­ing GPU code, will pay back mul­tiple times.

Build Mat­rix
And that’s just the top half.

Web is un­for­tu­nately just too damn slow

Ever since I made the light­weight Mag­num web­site and docs, the rest of the In­ter­net com­par­at­ively star­ted to feel much slower. While I can jump to a doc­u­ment­a­tion of MeshTools::gen­er­ateS­mooth­Nor­mals() in a frac­tion of a second, nav­ig­at­ing to a par­tic­u­lar is­sue of a par­tic­u­lar pro­ject through the Git­Hub UI to write a reply is so slow that it’s faster for me to just re­call its num­ber and type the whole ad­dress out.

For ex­tern­al lib­rar­ies I’m us­ing, I of­ten end up re­gen­er­at­ing the docs my­self us­ing m.css. The search func­tion­al­ity of any Sphinx-gen­er­ated docs is a bad joke and Googling the ac­tu­al be­ha­vi­or of Py­thon’s splitlines() isn’t nearly as straight­for­ward as it should be either. I ended up build­ing my own search­able copy of Ei­gen doc­u­ment­a­tion, did a sim­il­ar thing for An­droid NDK and I’m plan­ning to do that for Py­thon stand­ard lib­rary as well.

Worth men­tion­ing is Zeal, provid­ing off­line docs for vari­ous lib­rar­ies. I nev­er used it my­self, so can’t com­ment fur­ther.