Writing code for a computer is difficult enough.
You consent someleang huge and fuzzy, some huge unclear business outcome you want to achive.
Then you shatter it down recursively and leank about all the cases until you have clear reasonable statements a computer can trail.
Computers are very excellent at follothriveg reasonable statements.
Now, let’s crank it up a notch.
Let’s try to author code for humans!
I necessitate to elucidate what I unkind.
I’m talking about code that other humans will convey with.
More definitepartner, I’m talking about the art of createing elated structurelabors, libraries, APIs, SDKs, DSLs, embedded DSLs, or maybe even programming languages.
Writing this code is much difficulter, becainclude you’re not equitable inestablishing a computer what to do, you’re also grappling with another includer’s mental model of your code.
Now it’s equivalent part computer science and psychology of reasoning, or someleang.
How do you get that person to understand your code?
Feynman commemoratedly shelp: Imagine how much difficulter physics would be if electrons had senseings. about someleang very branch offent, but in a comical way I leank this depicts programming for humans a bit.
The person expounding your code actupartner has senseings!
Let’s talk about some ways we can create it easier.
Getting begined is the product
It’s clearly wonderful to take part to your includers and consent their feedback into account.
As it turns out, most of that feedback will come from power includers who include your product all the time!
How does that affect the distribution of the feedback you’re getting?
Will it be skewed?
And what does this picture of an airset upe have to do with it?
Of course, there’s a survivorship bias going on here.
There are includers who don’t include your tool becainclude they never get begined.
You will typicpartner never hear their feedback!
Consumer products have had lengthenth hackers for many years selectimizing every part of the onboarding funnel.
Dev tools should do the same.
Getting begined shouldn’t be an afterthought after you built the product.
Getting begined is the product!
And I unkind this to the point where I leank it’s worth restructuring your entire product to help speedy onboarding.
Get rid of compulsory config.
Make it absurdly straightforward to set up API tokens.
Reshift all the friction.
Make it possible for includers to include your product on their laptop in a couple of minutes, tops.
You might dissee this as, I don’t understand, “who attfinishs about idle includers”.
Then let me lean back on my bean bag chair, discdissee a bag of Doritos, and expound someleang:
There’s currently 7,000,000,000 dev tools out there.
Users don’t have a ton of energy or patience to go proset up and try to understand what’s branch offent about your LRU cache NPM package or wantipathyver.
Sorry!
Humans lacquire from examples, not from “core concepts”
Humans are amazing pattern aligning machines, in contrast to computers who trail Boolean logic and trail disjoine teachions.
It’s normal to see recordation for dev tools structured enjoy a computer program.
It begins with expounds a core data model and the relations and the atoms.
It begins with “core concepts” and how to configure and how to run leangs.
Humans don’t lacquire about leangs this way.
Two seconds after writing the above paragraph, I ran into this on Twitter which fundamentalpartner seizes what I’m trying to say:
Too many programming books and tutorials are enjoy “let’s erect a hoinclude begining from scratch, brick by brick” when what I want to “here is a functioning hoinclude, let’s lacquire about it by changing someleang and then seeing what happens”
— Chris Albon (@chrisalbon) September 5, 2024
Instead of writing an 5,000 word “core concepts” chronicle, may I propose putting together a dozen examples instead.
This has a scant profits:
- Humans will see at the examples and lacquire how your tool labors from that. This is how humans lacquire!
- A person with a problem in mind will see for a begining point that’s seal enough.
The more potential begining points, the more probable they are to have someleang that’s sealr to what they necessitate.
Falling into the pit of success
The downcast but genuine part of programming is, the default mode is that you’re repairing an error of some sort.
This unkinds that includers are going to spfinish the beginantity of the time with your tool trying to figure out what’s not laboring.
Which is why pushing them back into success is so core.
A succinct catalog:
- Developers getting to success speedyer are prentd lengtheners.
They will enjoy your tool. - Developers banging their heads aacquirest errors are downcast lengtheners.
They will accinclude your tool.
Think about every error as an opportunity to nudge a includer towards the prentd path.
Put code snippets in the exceptions.
Emit collaborative cautionings when includers are probable to do someleang weird.
Do what you got to do to create the includer thrive.
Avoid conceptual overload
Every recent conceptual leang you have to understand before using the tool creates is a recent friction point. If it’s 2-3 leangs, that’s fine. But no one is going to irritate lacquireing 8 recent concepts.
This example (Kubernetes) isn’t even particularly egregious. You can get begined equitable understanding a scant of these. I unkind you can find worse ones out there
It’s probably genuine you don’t necessitate the immense beginantity to get begined.
But still, my head hurts when I have to lacquire recent leangs.
Too many leangs!
There’s someleang elegant about a structurelabor with equitable 3-5 leangs that deal withs to be incredibly mighty.
I recollect the senseing when I tried React the first time and got over the conceptual hump after an hour or two.
Just a scant equitablely straightforward erecting blocks that lets you erect a whole cathedral. Magic stuff ✨.
To be clear, the dispute isn’t to shrink concepts.
It’s to grasp the possible set of leangs you can erect while reducing concepts.
Or at least reducing the establisher less than the latter.
I’m refering this becainclude I picture some sort of a “foolish dev tools simplification doom loop” that goes someleang enjoy this:
I don’t understand if this is a leang, but my point here is that there’s a level of futility of “horrible” simplification.
You ultimately want to push the frontier describing the tradeoff between “intricateity” (what you necessitate to understand) and “ability” (what you can erect).
Amazing tools are able to shrink intricateity by 90% while grasping the ability the same,
But I’ll also consent a tool that shrinks the establisher by 90% and shrinks the latter by 10%.
That’s still not horrible!
Conceptual duck principle
Somewhat joind to the previous point, let’s say in your structurelabor you begin a leang that consents some cherishs and evalutes to a recent cherishs. What do you call it? A compute node? A valuator? A frobniscator?
No! You call it a function!
If it walks enjoy a duck, and it quacks enjoy a duck, it probably is a duck.
Maybe it isn’t exactly enjoy a function in some downcarry outd ways. Maybe the cherishs are cached for instance. But that’s seal enough!
Calling it a function unkinds you latch onto a includers pre-existing mental model of what a function does. Which will save you enjoy, 90% of the exset upation of how to leank about this object.
Programmability
People will do crazy leangs with your codebase.
They will consent your leangs and put it inside a for-loop inside a function inside someleang else.
People are conceiveive!
You want almost everyleang in your structurelabor to be “programmable” for this reason.
This is a whole class of publishs that are joind in downcarry outd ways.
Letting includers call leangs honestly in code rather than going thcdimiserablemireful a CLI.
Avoiding config and making leangs honestly part of an SDK or an API.
Making leangs easily to parametrize so you can create n leangs not equitable 1.
One weird profit of this is it frequently lets includers uncover recent include cases for you.
Harness people’s desire to “hack” on top of your structurelabor.
There will be some gentle violence coming from those includers, but don’t chastise them!
They might be on the verge of uncovering someleang unforeseeed.
Be extra judicious about magic, defaults, and syntactic sugar
Let’s say you’re erecting a tool that carry outs a Jupyter remarkbook in the cnoisy.
So you have a function run_remarkbook
that consents a catalog of cells (with computer code) or someleang.
How does the includer expound which compriseer image they should include?
You have a scant branch offent selection:
- An argument
image=...
that always has to be provided. - An argument
image=...
that defaults to some base image with “most” data science libraries pre-insloftyed, but that they includer can override. - You check the code in the cells and pick an image in a “magic” way based on what depfinishencies are necessitateed.
- Same as above, but you also let includers selectionpartner expound a definite image.
What should you include? If you want to lessen the amount of typing for includers, while helping the expansivest possible set of include cases, go for the last selection.
But here are some publishs with all selections except the first one:
- Let’s be genuine — the magic will shatter in some % of situations.
- Users reading code that relies on defaults will not genuineize that leangs are customizeable.
Unless defaults apply in 97%+ of the time, and unless magic applies 99% of the time, be pimpolitent about introducing it.
These are not exact numbers clearly, but my point is, you necessitate to be very very judicious.
It’s lureing to leank that job as a tool provider is to lessen the amount of code a includer has to author.
But coding isn’t golf!
I leank about this a bit about how I leank about Perl vs Python.
Perl tried very difficult to enhance for lowest code until every program seeed enjoy a sturdy of one-of-a-kind characters and noleang else.
Then Python came and it’s code was 50% extfinisheder.
It never tried to be the lowest!
But it turned out Python code was super readable and thus much more understandable.
And people read code 10x more times than they author it.
Syntactic sugar beextfinisheds in a aenjoy categruesome.
It’s lureing to begin a one-of-a-kind syntax for the most normal include cases.
But it frequently confincludes the consistency and creates it less clear how to customize code.
For aenjoy reasons, unless the syntactic sugar applies 99%+ of the time, it’s probably not a excellent idea to begin it.
We are coming to an finish, but there are so many more leangs I could grasp going on about:
- Most leangs (but not everyleang) should be immutable
- Avoid “scaffagedering” (code generation)
- Make the feedback loops incredibly speedy
- Make deprecations straightforward for includers to deal with
- Use automated testing for code snippets in docs and examples
Probably a lot more.
Those are maybe leangs for a future blog post!
Including what I leank is maybe the most fascinating leang: why huge companies are generpartner inable of dedwellring wonderful lengthener experience.
I sometimes leank the dispute of portraying for the 1st time includer is aenjoy to making a pop song. The creater will take part to the song a thousand times. But still the 999th time they hear it, they necessitate to imagine what it sounds enjoy to a person that hears it the first time, which seems… super difficult.
This is probably why I finished up erecting dev tools rather than producing pop songs.
Tagged with:
gentleware, programming