10 interesting stories served every morning and every evening.

Reasonix — DeepSeek-native AI coding agent

esengine.github.io

50 Hours to Draw Some Lines

www.dougmacdowell.com

Description: I used to live on a quiet road on top of a huge hill. When leaves were on the trees it felt se­cluded, and when the leaves fell, the en­tire city would ap­pear be­low as sparkling lights. Sometimes, I’d run into a neigh­bor.

What are you work­ing on these days?”

Data vi­su­al­iza­tions.” I told him.

Ah, you us­ing al­go­rithms, ma­chine learn­ing, cloud com­put­ing, things like that?”

No.” I said. I’m just try­ing to draw a line graph.”

My neigh­bor thought I was get­ting into some com­plex sh**. But what’s been more in­ter­est­ing to me lately than us­ing

is learn­ing to draw data by hand. 50 Hours to Draw Some Lines is about spend­ing more than a week on some­thing that soft­ware can ac­com­plish in 20 min­utes - and a cat­a­log of re­sources and meth­ods ac­quired along the way.

What do I mean by draw­ing data by hand? I made this data vi­su­al­iza­tion (data viz) about a cof­fee maker com­puter by hand, us­ing rulers, pen­cils, ink, and a let­ter­ing kit. Along with my flubs, flukes, and ac­cli­ma­tion with tools - it took me 50 hours to make. It’s sta­tis­ti­cally ac­cu­rate, care­fully crafted, and like Hackaday said right out of a 1970′s col­lege text­book”. It’s how pro­fes­sion­als might vi­su­al­ize data be­fore com­put­ers could do it for them.

↑ A pro­fes­sional drafts­man of the 1920′s may cringe at the im­per­fec­tions in my line graph above. They can suck it.

There are books about hand drawn data viz, and these are my fa­vorite. Nearly all are avail­able on­line for free, and can be ref­er­enced for in­struc­tion/​in­spi­ra­tion. Tufte’s book sucked me in and spit me out as a hard­core data viz en­thu­si­ast. Dubois’ so­ci­o­log­i­cal and artis­tic ex­per­i­men­ta­tion are my fa­vorite to re­visit over again. Williard Brinton’s book from 1914 smells awe­some (it’s in my col­lec­tion). And William Willard’s in­struc­tions are blunt and to the point - I bet he was a cool shop teacher.

The Visual Display of Quantitative Information - Edward R. Tufte - 2001

W.E.B. Du Bois’s Data Portraits - Whitney Battle-Baptiste, Britt Rusert - 2018

Graphic Methods for Presenting Facts - Willard C. Brinton - 1914

Graphic Presentation - Willard C. Brinton - 1939

A Practical Course in Mechanical Drawing for Individual Study and Shop Classes - William Franklin Willard - 1910

Charts and Graphs - Karl G. Karsten - 1925

Engineering Drawing - Frank Zozzora - 1953

Freehand Drafting for Technical Sketching - Anthony E. Zipprich - 1924

↑↑ Is this art­work by Jiří Lindovský a data viz? Is it a nar­row sky­scraper? A Cheez-It? CPU? A line graph? … Whatever it is, this draw­ing was made us­ing the same tech­niques cov­ered here. By learn­ing to hand draw data viz, you can also learn about art. In fact, this whole thing is re­ally about mak­ing art. One of the best parts of art, is play­ing with tools.

These are the ba­sic tools and ma­te­ri­als needed to hand draw data viz…

Paper - smooth bris­tol is best, 14 x 17 in. or larger

T-square - pro­vides a level guide for your draw­ing

Ruler - it’s im­por­tant to have a mea­sure­ment tool

Drawing board - I use ce­ment board from a hard­ware store, at least 3 x 3 ft pre­ferred

Painter’s tape - must-have for hold­ing pa­per and t-square down, I like the wide va­ri­ety

Pencils - a clas­sic me­chan­i­cal BIC is my fa­vorite

Pens - most any­thing works, I like Micron pens

Eraser - eras­ing graphite to re­veal crisp ink lines is a spe­cial thing, Staedler erasers are great

Triangle - slides along the t-square, used to draw ver­ti­cal lines and an­gles

Circle sten­cil - very im­por­tant tool, this is used to cre­ate con­sis­tent line weights

Ink - this one with a spi­der per­son is my fa­vorite

Lettering kit - not re­quired, but a very fun vin­tage tool to cre­ate nice let­ter­ing

To start a hand drawn data viz, be­gin with a grid. Drawing a grid is not only a nec­es­sary first step, but a calm, mind­ful process to en­joy while be­com­ing com­fort­able with the tools. Practice by po­si­tion­ing pa­per on the draw­ing board us­ing the t-square as a level. Cut a long piece of tape and wrap it around your torso and spin around 3 times (the fuzzies from your clothes help avoid the tape stick­ing too much to the pa­per). Then place the tape hor­i­zon­tally across the top edge of the pa­per, hold­ing it in place.

Adding mar­gins is al­ways a good idea and will es­tab­lish the work­space. If the pa­per is 20 x 24 inches, mea­sure one inch in on each side. Using a pen­cil, t-square, ruler, and tri­an­gle, draw some mar­gin lines. The new work­space is 18 x 22 inches. Keep go­ing, us­ing a ruler, make a mark every inch on the mar­gin lines and us­ing the straight edge tools again, make lines at each mark. There are now 396 squares map­ping out the work­space. Call it a night, or di­vide the squares even more, and draw more lines. Everything done to cre­ate hand drawn data comes back to this grid. In the end, all the pen­cil lines will be erased, re­veal­ing the most sat­is­fy­ing, clean, crisp inked lines imag­in­able. But we’re not there yet.

When I started, I thought I’d use a fat marker like a Sharpie to draw the lines of my line graph. That does­n’t work. It’s nearly im­pos­si­ble to cre­ate a qual­ity line with the stroke of a pen alone. I needed a way to con­trol the weight of the line and cleanly con­nect every data point ac­cu­rately. I found that the best way to make a pro­fes­sional, proper data line, is to use cir­cles.

↑ Using a pen­cil, plot data points onto the grid with a small dot. Grab a cir­cle sten­cil and cre­ate a cir­cle around each dot - this sets the line weight. With a debit card (or a small ruler), con­nect the outer edge of one cir­cle, with the cir­cle next to it. It’s sur­pris­ing how in­tu­itive this feels while see­ing the lines be­gin to form. I like my con­nec­tor lines to over­lap slightly, let­ting me con­trol the style of line joins (miter/bevel/round).

↓ A while back I was walk­ing alone in an al­ley­way when a large, off-leash rot­tweiler ap­peared and stared me down. I felt scared. Thankfully, the rot­tweiler was in­ter­ested in some­thing else and went on his way. At this stage it’s time to use ink, and it can feel scary. (carefully) Trace over the con­nec­tor lines in ink us­ing a pen. Like how the rot­tweiler left and my fear re­lieved, the same feel­ing hap­pened here. At this point, I re­ward my­self with a treat, and give one to the rot­tweiler too.

Using an eraser and a light touch, be­gin eras­ing the pen­cil marks near the lines. The ink should stay in place, the pen­cil lines dis­ap­pear, and en­dor­phins surge from the brain. Coloring in the lines with a pen or paint brush is the last step to fin­ish the lines of the graph. But! Lines are just part of a data viz. To make it com­plete a few fi­nal touches are needed.

A de­bate among artists is whether or not to sign their work. Alphonse Mucha promi­nently signed much of his work, but his sig­na­ture is al­most hid­den in his most mon­u­men­tal paint­ings. Data viz guru Edward Tufte (aka ET) be­lieves a vivid dis­play of au­thor­ship is es­sen­tial. Marcel Duchamp signed a uri­nal.

Signature or not, the choice of text el­e­ments is im­por­tant. Text can be added free-hand, or with a tool called a let­ter­ing kit. When I bought my let­ter­ing kit I did­n’t know what all the lit­tle pieces were that came with it. If some were miss­ing from the kit would it mat­ter? Definitely. The small metal pieces are reser­voirs and nibs. The reser­voir holds the ink, and the nib sits in­side the reser­voir, con­trol­ling the ink be­ing let out. They are dif­fer­ent sizes and need to match. These need cleaned out af­ter each use - soap, wa­ter, tooth brush, and com­puter duster did the trick for me.

Adding a ti­tle, axis la­bels, an­no­ta­tions, and au­thor­ship (if you choose) are the fi­nal el­e­ments needed to fin­ish the hand drawn data viz! The re­main­ing pen­cil marks can be erased, leav­ing only ink. I found that I ac­tu­ally like leav­ing some pen­cil marks from the grid as an ar­ti­fact of the process, and a clue that this is some­thing made by hand.

At this point, I sit back and en­joy my hard work.

I don’t live on a quiet road on top of a huge hill any­more. I ac­tu­ally live down­town in a city and my life and work are quite dif­fer­ent. I query data­bases that have gath­ered data for a long time - this is some­times com­pli­cated work. Like many peo­ple, I can’t spend my time draw­ing data. However, my time de­voted to hand draw­ing data has left me with a ques­tion that won­der­fully im­pacts me each time I think about it…

Why did I spend 50 hours mak­ing some­thing that PowerPoint could make in 20 min­utes?

Subscribe

AI Chip Component Costs: Memory at 63% | Epoch AI

epoch.ai

Epoch’s work is free to use, dis­trib­ute, and re­pro­duce pro­vided the source and au­thors are cred­ited un­der the Creative Commons BY li­cense.

Learn more about this graph

For each AI chip de­signed by Nvidia, AMD, Google, and Amazon, we es­ti­mate the per-chip cost of four com­po­nent cat­e­gories: mem­ory (HBM), logic dies, ad­vanced pack­ag­ing (CoWoS), and aux­il­iary com­po­nents. We then mul­ti­ply those per-chip costs by es­ti­mated quar­terly pro­duc­tion vol­umes to get to­tal com­po­nent spend­ing in each cat­e­gory, and com­pute each cat­e­go­ry’s share of to­tal com­po­nent spend­ing per quar­ter from Q1 2024 to Q4 2025.

We find that mem­o­ry’s share rose from 52% to 63% over this pe­riod, while pack­ag­ing fell from 19% to 15% and aux­il­iary com­po­nents from 15% to 9%. Logic die share stayed roughly con­stant near 13 – 14%. Total com­po­nent spend on AI chips grew from ap­prox­i­mately $22 bil­lion in 2024 to $52 bil­lion in 2025, with HBM spend­ing alone ac­count­ing for roughly $20 bil­lion of that in­crease.

Data

Analysis

Assumptions and lim­i­ta­tions

Download this data

AI chip com­po­nent cost shares by quar­ter

CSV, Updated May 21, 2026

Explore this data

AI Chip Components

AI chip sup­ply chain con­sump­tion data.

AudioMass

audiomass.co

The Eternal Sloptember

geohot.github.io

I’m call­ing it now, the adop­tion of AI agents into soft­ware de­vel­op­ment will be one of the most costly mis­takes in the field’s his­tory. Agents can­not pro­gram, and it’s tak­ing longer and longer to re­al­ize that they can’t. They are a highly so­phis­ti­cated sta­tis­ti­cal model de­signed to mimic the dis­tri­b­u­tion of pro­gram­ming. The out­put is bro­ken, but in a way that’s get­ting harder and harder to de­tect. Which is ex­actly what you’d ex­pect from an in­creas­ingly ac­cu­rate sta­tis­ti­cal model.

At first, I re­jected this. I bought into the Twitter ex­pla­na­tion of sta­tus anx­i­ety. I de­fine some of my self worth by my pro­gram­ming abil­i­ties, so would­n’t it make sense to get de­fen­sive around that loss? Deny the mod­els can code for as long as I could to pre­serve my ego?

I mean, it’s very clear they can solve math prob­lems I could­n’t hope to solve if I de­voted my life to it. So why can’t they pro­gram? Maybe I’m just not good enough of a pro­gram­mer to rec­og­nize their ge­nius.

I re­ally tried for the last 6 months. I wrote some parts of tiny­grad with agents. I re­versed a USB <-> PCIe chip with agents. But each time I sus­pected I could have done it bet­ter and faster man­u­ally. The agent front­loads all the progress, then gives you a slot ma­chine lever to pull to hope it gets the pol­ish done. It never quite gets there.

And in be­fore, you are us­ing it wrong.” I have tried all the dif­fer­ent mod­els, dif­fer­ent har­nesses, dif­fer­ent prompts. It’s not this. The peo­ple who say this would prob­a­bly say the same thing about slot ma­chines, you see, you have to bet 5 lines af­ter you get a cherry no won­der you aren’t win­ning!

I’m not say­ing that AI is­n’t use­ful, it clearly is. It’s def­i­nitely a bet­ter Google for most searches. And when­ever you need a quick pro­to­type and don’t care about pol­ish, it is ab­surdly fast. But is it a soft­ware en­gi­neer? Not close to the bar at any com­pany I have worked at. The key as­pect is know­ing when to use it and when not to.

I thought more about the self worth preser­va­tion thing. AFL found more bugs than LLMs and no­body felt that way about it. Chess and Go are more pop­u­lar than ever. I can­not fuck­ing wait un­til I have armies of ro­bot as­so­ci­ates I can trust to clean up my code! I don’t fear loss of sta­tus, I al­most think this is some kind of psyop to sell agents. Fear of loss is one of the only ways to make big com­pa­nies move. Though I think in that fear they are mak­ing a big mis­take.

Agents will end up hurt­ing large or­ga­ni­za­tions more than high per­form­ing in­di­vid­u­als or small orgs. I’ve watched how my friends and cowork­ers have adopted these tools over the last 6 months. A trait you find in all high per­form­ing peo­ple is the abil­ity to er­ror cor­rect, and they have mostly been good at see­ing when slop is slop. It takes a bit to ex­plore/​ex­ploit and tune the outer loops around when to use them, when to trust them, how to use them, etc…but I haven’t seen any­one of them move to a model where they don’t care­fully read and un­der­stand each line, ex­cept in some con­fined do­mains.

Contrast this with a large or­ga­ni­za­tion. Much slower feed­back loops, much less align­ment. The bot­tom per­form­ers won’t have that self check. They are the ones pro­duc­ing 10x out­put with the agents. What do you think is hap­pen­ing to the av­er­age out­put of that or­ga­ni­za­tion? What is hap­pen­ing to the av­er­age out­put of the world?

Agents will end up pro­duc­ing more code, more apps, and more fea­tures than ever be­fore. It is a golden era for buck­ets and buck­ets of slop, and a dark age for gems of qual­ity.

I hear that Apple is push­ing AI on all their en­gi­neers. When peo­ple think in the ab­stract, they think AI will do all this stuff, but let’s fo­cus on a con­crete ex­am­ple. Do you think ma­cOS will get bet­ter or worse in the next 2 years?

When peo­ple see an ar­ti­fact, they make as­sump­tions about the process that was used to cre­ate it. Without even think­ing about it, they as­sume the cre­ator had a ba­si­cally hu­man state of mind. This as­sump­tion is no longer true. Things can be bro­ken in ways that weren’t pre­vi­ously pos­si­ble, and old prox­ies of un­der­ly­ing qual­ity like syn­tax and gram­mar are use­less. AI pro­duced ar­ti­facts are not pro­duced by the same process as hu­man ones, and this dif­fer­ence, while ex­tremely sub­tle in sta­tis­tics, makes it­self ob­vi­ous when you try to in­ter­act with and build on the ar­ti­fact in hu­man ways.

Without fully en­dors­ing all their ideas, I’m now in the LeCun/Marcus camp on LLMs. I don’t think mod­els like this will ever be able to pro­gram, I think the process mat­ters. I think that deep learn­ing is still the so­lu­tion, but real pro­gram­ming agents will need world mod­els, not some RLVR shit that com­ments out the fail­ing test and tells you all the tests are now pass­ing.

The real story of this era will be who man­ages to avoid harm­ing them­selves in their AI psy­chosis.

Claude Is Not Your Architect. Stop Letting It Pretend.

www.hollandtech.net

I’ve seen it three times in the last month. Three dif­fer­ent or­gan­i­sa­tions, three dif­fer­ent tech stacks, the same pat­tern.

Someone has an idea. Maybe a prod­uct man­ager, maybe a team lead, maybe the CTO af­ter a con­fer­ence. They open Claude, or ChatGPT, or Copilot — does­n’t mat­ter which — and ask it what they should build. The AI does what it al­ways does: val­i­dates the idea en­thu­si­as­ti­cally, sug­gests an ar­chi­tec­ture, and starts sketch­ing com­po­nents. It’s ar­tic­u­late. It’s con­fi­dent. It sounds like a very se­nior en­gi­neer who’s thought deeply about the prob­lem.

It has­n’t thought about the prob­lem at all. It’s pat­tern-match­ing against its train­ing data and pro­duc­ing the most plau­si­ble-sound­ing re­sponse. But it sounds so good that no­body pushes back.

Before you know it, Claude is the ar­chi­tect.

The at­taboy prob­lem

AI agents are patho­log­i­cally agree­able. Ask Claude if your idea is good and it’ll tell you it’s good. Ask it if a mi­croser­vices ar­chi­tec­ture makes sense for your three-per­son team and it’ll ex­plain why mi­croser­vices are an ex­cel­lent choice. Ask it if you should build a cus­tom ML pipeline in­stead of us­ing a man­aged ser­vice and it’ll en­thu­si­as­ti­cally lay out the de­sign.

It’s not ly­ing. It’s not even wrong, nec­es­sar­ily. It’s just in­ca­pable of the thing that makes a real ar­chi­tect valu­able: say­ing no.”

A good ar­chi­tec­t’s most im­por­tant skill is­n’t de­sign­ing sys­tems. It’s know­ing which sys­tems not to build. It’s push­ing back on com­plex­ity. It’s ask­ing why?” five times un­til the ac­tual re­quire­ment emerges from the as­pi­ra­tional non­sense. It’s telling the CTO that their con­fer­ence-in­spired idea is a ter­ri­ble fit for the team they ac­tu­ally have.

Claude will never do this. It’s trained to be help­ful. Helpful means agree­able. Agreeable means you get an at­taboy and a Jenga tower that passes for ar­chi­tec­ture.

The Jenga tower

Here’s what the AI-designed ar­chi­tec­ture looks like in prac­tice.

It’s tech­ni­cally sound. The com­po­nents make sense in iso­la­tion. The pat­terns are recog­nis­able — event-dri­ven here, CQRS there, a ser­vice mesh be­cause why not. It looks like some­thing a se­nior ar­chi­tect would pro­duce. It passes the squint test.

But it was­n’t de­signed for your team. It was­n’t de­signed for your con­straints. It was­n’t de­signed for the bor­ing re­al­ity of your pro­duc­tion en­vi­ron­ment — the VPC lock­downs, the legacy in­te­gra­tions, the team that’s never op­er­ated Kubernetes in pro­duc­tion, the com­pli­ance re­quire­ments that mean half the man­aged ser­vices are off-lim­its.

It was de­signed for the me­dian of every­thing Claude has seen. A generic best prac­tice for a generic prob­lem at a generic com­pany. Which is to say, it was de­signed for no­body.

Real ar­chi­tec­ture is full of trade-offs that only make sense in con­text. You pick Postgres over DynamoDB be­cause your team knows Postgres and you’d rather ship in two weeks than spend a month learn­ing a new data model. You skip the ser­vice mesh be­cause you’ve got four ser­vices, not forty. You use a mono­lith be­cause the prob­lem is sim­ple and mi­croser­vices would be ca­reer-dri­ven de­vel­op­ment.

These de­ci­sions re­quire judge­ment. They re­quire know­ing the team. They re­quire un­der­stand­ing the or­gan­i­sa­tion’s ac­tual con­straints, not the ones that look good on a white­board. An AI agent has none of this con­text, and worse — it does­n’t know it does­n’t have it.

The Jira ticket pipeline

The bit that re­ally wor­ries me is what hap­pens next.

Once Claude has de­signed the ar­chi­tec­ture, the same peo­ple who asked it for the de­sign ask it to break the work down. It pro­duces epics. Stories. Acceptance cri­te­ria. Neatly for­mat­ted, well-rea­soned, ready to drop into Jira.

And now the en­gi­neers — the peo­ple who’ve spent years hon­ing their craft, who un­der­stand the do­main, who know where the bod­ies are buried — are no longer solv­ing prob­lems. They’re im­ple­ment­ing Claude’s de­sign, one ticket at a time.

Think about what’s hap­pened here. The peo­ple with the most con­text, the most ex­pe­ri­ence, and the most skin in the game have been re­duced to ticket im­ple­menters. The en­tity with the least con­text, no ex­pe­ri­ence, and no ac­count­abil­ity is mak­ing the ar­chi­tec­tural de­ci­sions.

It’s not just in­ef­fi­cient. It’s back­wards.

But some­one se­nior signed off”

This is the de­fence I hear most of­ten. Claude sug­gested the ap­proach, but a se­nior en­gi­neer re­viewed it.”

Let’s be hon­est about what reviewed it” means in prac­tice. A busy tech lead gets handed a well-ar­tic­u­lated ar­chi­tec­tural pro­posal. It’s co­her­ent. It uses the right ter­mi­nol­ogy. It ad­dresses the stated re­quire­ments. The di­a­grams make sense. It looks like some­thing they might have de­signed them­selves.

How much push­back are they go­ing to give? In a world where the re­sponse to I don’t think this is right” is Claude spent twenty min­utes on this and you want to throw it away?”, the path of least re­sis­tance is to ap­prove it with mi­nor com­ments.

This is the real dan­ger. Not that AI pro­duces bad ar­chi­tec­tures — it of­ten pro­duces per­fectly rea­son­able ones. The dan­ger is that it short-cir­cuits the dis­cus­sion. The messy, ar­gu­men­ta­tive, time-con­sum­ing process where three en­gi­neers dis­agree about the ap­proach, where some­one says what about…” and every­one groans but then re­alises it’s a good point, where the fi­nal de­sign is bet­ter than any­thing one per­son would have pro­duced — that process gets re­placed by Claude said so.”

The ac­count­abil­ity gap

Here’s the ques­tion no­body’s ask­ing: when it goes wrong, who car­ries the bag?

Not Claude. Claude does­n’t have a bag. Claude does­n’t get paged at 3am. Claude does­n’t sit in the post-in­ci­dent re­view ex­plain­ing why the ar­chi­tec­ture could­n’t han­dle the load. Claude does­n’t have to tell the CTO that the plat­form needs to be rewrit­ten be­cause the orig­i­nal de­sign as­sump­tions were wrong.

Your en­gi­neers do. The same en­gi­neers who did­n’t de­sign it. The same en­gi­neers who were im­ple­ment­ing tick­ets writ­ten by an en­tity that’s never op­er­ated a sys­tem in pro­duc­tion. They’re the ones stay­ing late, de­bug­ging an ar­chi­tec­ture they did­n’t choose, in a code­base that was scaf­folded faster than any­one could un­der­stand it.

That’s not fair. And it’s not smart.

What to do in­stead

I’m not say­ing don’t use AI agents. I use Claude Code every day. It’s trans­formed my pro­duc­tiv­ity. But I use it the way you’d use any pow­er­ful tool — I tell it what to do, not the other way round.

Engineers de­sign. Agents im­ple­ment. The ar­chi­tec­ture comes from peo­ple who un­der­stand the con­text — the team, the con­straints, the pro­duc­tion en­vi­ron­ment, the or­gan­i­sa­tional pol­i­tics. The AI helps them build it faster. That’s the right di­vi­sion of labour.

Challenge the at­taboy. When an AI sug­gests an ap­proach, treat it with the same scep­ti­cism you’d ap­ply to a con­fi­dent ju­nior en­gi­neer. It might be right. It might also be pat­tern-match­ing against some­thing that does­n’t ap­ply to your sit­u­a­tion. Ask why not the sim­pler op­tion?” and see what hap­pens.

Protect the ar­gu­ment. The messy dis­agree­ment be­tween en­gi­neers is where good ar­chi­tec­ture comes from. If AI is short-cir­cuit­ing that process — if peo­ple are de­fer­ring to Claude in­stead of de­bat­ing with each other — you’ve lost some­thing far more valu­able than de­vel­op­ment speed.

Keep hu­mans ac­count­able. If a hu­man’s name is­n’t on the ar­chi­tec­tural de­ci­sion, no­body owns it. And if no­body owns it, no­body will fight for it when it mat­ters. Claude de­signed it” is not an ar­chi­tec­ture de­ci­sion record. It’s an ab­di­ca­tion.

The craft still mat­ters

Thirty years ago, when I started in this in­dus­try, the tool was a white­board and a strong opin­ion. Today the tool is an AI agent that can pro­duce in min­utes what used to take days. The speed is gen­uinely re­mark­able.

But the craft has­n’t changed. Understanding the prob­lem. Knowing the con­straints. Making trade-offs. Defending the sim­ple so­lu­tion against the ex­cit­ing one. Saying no” to the idea that sounds great but does­n’t fit.

That’s ar­chi­tec­ture. No agent does it. If you’ve let Claude take the wheel, take it back.

Your en­gi­neers have spent years build­ing the judge­ment to make these calls. Let them make them. Use the AI to build faster. But build what your peo­ple de­signed — not what the ma­chine sug­gested.

Because when the Jenga tower wob­bles — and it will — Claude won’t be there to catch it.

Australia Just Proved the Four-Day Work Week Works. Here Is What the Data Actually Says.

scienceaim.com

A new study pub­lished in Nature’s Humanities and Social Sciences Communications jour­nal has con­firmed what many work­ers have qui­etly hoped for: com­pa­nies can switch to a four-day work week and not only sur­vive, but thrive.

The re­search tracked 15 Australian com­pa­nies that tri­alled the 100:80:100 model be­tween 2022 and 2024.

The model is sim­ple: work­ers re­ceive 100% of their pay, work 80% of their pre­vi­ous hours, and com­mit to main­tain­ing 100% of their pre­vi­ous out­put.

The re­sults were strik­ing.

14 of the 15 com­pa­nies chose to con­tinue with the four-day week af­ter the trial ended.

Not a sin­gle one re­ported a drop in pro­duc­tiv­ity.

Six com­pa­nies saw pro­duc­tiv­ity ac­tu­ally in­crease.

The rest said out­put stayed roughly the same.

These firms op­er­ated across a wide range of in­dus­tries, from prop­erty man­age­ment to pub­lish­ing and health tech­nol­ogy, which makes the find­ings harder to dis­miss as a niche ex­per­i­ment.

How the Study Was Conducted

The re­search team, led by Professor John Hopkins of Deakin University, spent two years con­duct­ing in-depth in­ter­views with com­pa­nies that had for­mally adopted the 100:80:100 model.

Interviews took place be­tween early 2023 and late 2024.

Each com­pany was free to de­fine pro­duc­tiv­ity on its own terms.

Some mea­sured rev­enue and profit.

Others tracked pro­jects com­pleted on time, staff turnover rates, ab­sen­teeism, or a met­ric called net pro­moter score,” which gauges how likely cus­tomers are to rec­om­mend a busi­ness.

This flex­i­bil­ity was in­ten­tional.

Rather than im­pos­ing a sin­gle per­for­mance bench­mark, the re­searchers al­lowed each com­pany to mea­sure what mat­tered most to them.

That de­sign choice re­flects some­thing im­por­tant: what suc­cess looks like dif­fers by in­dus­try, and a rigid, one-size-fits-all mea­sure­ment would have made the find­ings less ap­plic­a­ble to the real world.

One com­pany had al­ready been run­ning the four-day model for nearly eight years by the time re­searchers in­ter­viewed them.

One firm did aban­don the trial, though the re­searchers noted that tim­ing played a sig­nif­i­cant role in that de­ci­sion, as the com­pany was al­ready go­ing through a pe­riod of ma­jor in­ter­nal change.

Findings From the Study

The head­line find­ing is clear: not one com­pany re­ported a pro­duc­tiv­ity loss.

Six of the 15 com­pa­nies said pro­duc­tiv­ity had ac­tu­ally gone up since mak­ing the switch.

The re­main­ing nine said it stayed about the same.

Those might sound like mod­est num­bers, but con­sider what they mean in prac­tice.

If you give your em­ploy­ees a full ex­tra day off each week, main­tain their salaries, and your out­put ei­ther stays the same or im­proves, the busi­ness case is dif­fi­cult to ar­gue against.

Burnout emerged as a ma­jor theme in the find­ings.

Six com­pa­nies ex­pressly said that re­duc­ing burnout, rather than boost­ing pro­duc­tiv­ity, was their pri­mary mo­ti­va­tion for adopt­ing the shorter week.

That dis­tinc­tion mat­ters.

A 2025 sur­vey by Beyond Blue found that one in two Australian work­ers cur­rently ex­pe­ri­ences burnout, with young peo­ple and par­ents iden­ti­fied as the groups most at risk.

One CEO of a medium-sized health tech­nol­ogy firm told re­searchers she judged the tri­al’s suc­cess by track­ing lev­els of attrition,” absenteeism,” and people tak­ing sick days and men­tal health days be­cause they’re burnt out.”

Another CEO at a fi­nan­cial ser­vices firm put it plainly: her com­pany had been en­cour­ag­ing clients to live their best lives, and it felt wrong to hold em­ploy­ees to a dif­fer­ent stan­dard.

As we grap­ple with high work­place burnout, and so­ci­etal chal­lenges about what to do with the pro­duc­tiv­ity gains we’re pre­dicted to get from AI, a four-day work week could be an in­ter­est­ing part of both those con­ver­sa­tions,” said study lead Prof John Hopkins of Deakin University.

What Most People Get Wrong About This Model

Here is the part that tends to get lost in the con­ver­sa­tion.

Most peo­ple hear four-day work week” and imag­ine com­pa­nies tak­ing a leap of faith, cross­ing their fin­gers, and hop­ing pro­duc­tiv­ity does not col­lapse.

The re­al­ity is quite dif­fer­ent.

The 100:80:100 model is not sim­ply about cut­ting a day.

It is about forc­ing com­pa­nies and their em­ploy­ees to look hon­estly at how time is ac­tu­ally be­ing spent.

Unnecessary meet­ings get cut.

Tasks that could be au­to­mated or del­e­gated get re­as­signed.

Work that was never that valu­able gets elim­i­nated en­tirely.

The re­sult is that em­ploy­ees are not cram­ming five days of work into four.

They are do­ing four days of gen­uinely fo­cused, higher-qual­ity work.

This is a cru­cial dis­tinc­tion, and it ex­plains why con­cerns about pro­duc­tiv­ity of­ten prove un­founded.

The fear that work­ers will sim­ply burn through five days of tasks in a com­pressed time­frame is rooted in a mis­un­der­stand­ing of how the model ac­tu­ally works.

Companies us­ing this ap­proach re­struc­ture their work­flows be­fore the shorter week be­gins.

Australia is not alone in see­ing this play out.

In 2024, 45 German com­pa­nies tri­alled the four-day model, and the ma­jor­ity were small or medium en­ter­prises.

Financial per­for­mance dur­ing the trial showed no sig­nif­i­cant dif­fer­ence from the year be­fore, which re­searchers in­ter­preted as ev­i­dence of pro­duc­tiv­ity gains since the same out­put was be­ing de­liv­ered in fewer hours.

In the United Kingdom, more than 200 British com­pa­nies have per­ma­nently adopted the four-day week with­out re­duc­ing pay, span­ning in­dus­tries from tech star­tups to char­i­ties.

How the Study Applies to Real Life

The prac­ti­cal ques­tion for most work­ers and man­agers is not whether the data is com­pelling.

It is whether the model is ac­tu­ally work­able in their spe­cific in­dus­try or role.

The Australian study pro­vides some use­ful in­sight here.

Client-facing or­gan­i­sa­tions han­dled the tran­si­tion dif­fer­ently from non-client-fac­ing ones.

Instead of all staff tak­ing the same day off, many com­pa­nies in client-heavy in­dus­tries stag­gered days off across the team, en­sur­ing clients al­ways had some­one avail­able.

That flex­i­bil­ity is cen­tral to why the model held up across such dif­fer­ent busi­ness types.

It is also why the con­ver­sa­tion can­not be re­duced to a sim­ple yes or no.

A law firm and a soft­ware de­vel­op­ment stu­dio will im­ple­ment a four-day week very dif­fer­ently.

A call cen­tre and a pub­lish­ing house have com­pletely dif­fer­ent rhythms.

The re­search sug­gests that the most suc­cess­ful adop­tions in­volve co-de­signed so­lu­tions where em­ploy­ees and lead­er­ship fig­ure out to­gether what re­struc­tur­ing ac­tu­ally looks like.

One of the more for­ward-look­ing threads in the re­search in­volves ar­ti­fi­cial in­tel­li­gence.

As AI tools con­tinue to au­to­mate repet­i­tive tasks and boost in­di­vid­ual out­put, the ques­tion of what work­ers do with those pro­duc­tiv­ity gains be­comes ur­gent.

The four-day week is one an­swer: let peo­ple re­claim some of that time rather than sim­ply adding more tasks to the same work­day.

Prof Hopkins specif­i­cally named this as a rea­son the con­ver­sa­tion mat­ters right now.

The as­sump­tion that tech­nol­ogy al­ways means do­ing more with the same num­ber of hours is worth ques­tion­ing.

The Criticism Worth Taking Seriously

The case for the four-day week is strong, but it is not with­out le­git­i­mate push­back.

Some re­searchers note that the ben­e­fits ob­served in short-term tri­als may not hold long-term.

There is a real pos­si­bil­ity that the pro­duc­tiv­ity gains seen in tri­als are partly dri­ven by the nov­elty ef­fect, where em­ploy­ees work harder be­cause they are aware they are be­ing ob­served or be­cause the change feels ex­cit­ing and new.

There is also the ques­tion of in­dus­tries where a four-day model is struc­turally harder to im­ple­ment.

Healthcare, emer­gency ser­vices, lo­gis­tics, and hos­pi­tal­ity do not run on fixed sched­ules in the same way a knowl­edge-work busi­ness does.

Any pol­icy con­ver­sa­tion about short­en­ing the work­ing week needs to reckon hon­estly with those sec­tors, not pre­tend they do not ex­ist.

Scheduling com­pli­ca­tions are real, par­tic­u­larly for client-fac­ing busi­nesses and teams spread across dif­fer­ent time zones.

The re­search also ac­knowl­edged that in­di­vid­ual com­pa­nies, not a re­search team, de­fined what pro­duc­tiv­ity meant, which makes di­rect com­par­i­son be­tween com­pa­nies dif­fi­cult.

None of this un­does the ev­i­dence.

But it does sug­gest the con­ver­sa­tion needs to be more nu­anced than sim­ple cel­e­bra­tion.

The Bigger Picture

What makes this Australian study par­tic­u­larly valu­able is not just the find­ings.

It is what the find­ings re­veal about the as­sump­tions un­der­neath how most of us work.

The five-day, 40-hour week was not handed down as a law of na­ture.

It was a labour move­ment achieve­ment, stan­dard­ised in the 20th cen­tury as in­dus­tri­al­i­sa­tion scaled up.

The con­di­tions of work have changed dra­mat­i­cally since then.

Knowledge work, re­mote col­lab­o­ra­tion, and AI-assisted tasks have trans­formed what a pro­duc­tive hour ac­tu­ally looks like.

The 15 Australian com­pa­nies in this study ef­fec­tively ran a live ex­per­i­ment on that as­sump­tion, and the data came back in favour of change.

Not one of them re­ported falling be­hind.

Most of them ei­ther held steady or im­proved.

And 14 of 15 chose not to go back.

That is not a fluke.

That is a sig­nal worth pay­ing at­ten­tion to, whether you are a man­ager won­der­ing if your team could han­dle it, an em­ployee hop­ing your com­pany will con­sider it, or a pol­i­cy­maker think­ing about what the fu­ture of work should ac­tu­ally look like.

The con­ver­sa­tion is no longer the­o­ret­i­cal.

It is al­ready hap­pen­ing.

The only ques­tion left is who joins it next.

References and Further Reading

Nature: Four-day work week study, Deakin University

The Conversation: 15 Australian com­pa­nies switched to a four-day work week

Positive News: The re­sults of the world’s largest four-day week trial

Beyond Blue: Workplace Burnout Survey 2025

Migrating from Go to Rust | corrode Rust Consulting

corrode.dev

Out of all the mi­gra­tions I help teams with, Go to Rust is a bit of an out­lier. It’s not a ques­tion of is Rust faster?” or does Rust have types?”, Go al­ready gets you most of the way there. The dis­cus­sion is mostly about cor­rect­ness guar­an­tees, run­time trade­offs, and de­vel­oper er­gonom­ics.

A quick dis­claimer be­fore we start: this guide is heav­ily back­end-fo­cused. Backend ser­vices are where Go is strongest, small sta­tic bi­na­ries, a stan­dard li­brary fo­cused on net­work­ing, and an ecosys­tem of li­braries for HTTP servers, gRPC, data­bases, etc.

That’s also where most teams con­sid­er­ing Rust are com­ing from (at least the ones who reach out to me), so I think that’s the com­par­i­son that’s ac­tu­ally use­ful in prac­tice. If you’re writ­ing CLI tools, em­bed­ded firmware, or game en­gines, some of this still ap­plies, but to be hon­est, I’m afraid this is not the best re­source for you.

For con­text, I’ve writ­ten about Go and Rust be­fore: Go vs Rust? Choose Go.” back in 2017, and later the Rust vs Go: A Hands-On Comparison” with the Shuttle team, which walks through a small back­end ser­vice in both lan­guages.

Where Go and Rust over­lap, and where they di­verge.

How Go pat­terns map to Rust.

What you gain from the bor­row checker.

Where I tell peo­ple to keep Go and where Rust is worth the mi­gra­tion cost.

How to mi­grate Go ser­vices in­cre­men­tally.

Where I’m Coming From

I’ll be up­front: I’m not a fan of Go. I think it’s a badly de­signed lan­guage, even if a very suc­cess­ful one. It con­fuses eas­i­ness with sim­plic­ity, and sev­eral of its core de­sign trade­offs (nil every­where, er­ror han­dling as a dis­ci­pline rule rather than a type, the long ab­sence of gener­ics) point in a di­rec­tion I dis­agree with. That said, suc­cess mat­ters! Go has cap­tured a real and per­sis­tent share of work­ing de­vel­op­ers, hov­er­ing around 17 – 19% in the JetBrains Developer Ecosystem Survey. Rust is grow­ing steadily but is still a smaller slice:

Go is clearly work­ing for a lot of peo­ple, and a guide that pre­tends oth­er­wise is­n’t help­ful. So I’ll do my very best to be ob­jec­tive in this guide rather than re­lit­i­gate old ar­gu­ments. But you should know my pri­ors so you can cal­i­brate.

The other prior worth dis­clos­ing: I run a Rust con­sul­tancy; of course I’m bi­ased! More peo­ple us­ing Rust is good for my busi­ness. But I’ve also worked in both lan­guages pro­fes­sion­ally and shipped Go ser­vices to pro­duc­tion.

This guide is for Go de­vel­op­ers who want an hon­est, side-by-side look at what changes when you move to Rust.

For a de­lib­er­ately op­po­site take, I rec­om­mend read­ing Just Fucking Use Go” by Blain Smith. Holding both views in your head at once is more use­ful than ei­ther one alone.

If you pre­fer to watch rather than read, here’s a video from the Shuttle ar­ti­cle above, read and com­mented by the Primeagen:

A First Look At The Most Important Commands

Go de­vel­op­ers al­ready have one of the clean­est tool­chains in the in­dus­try. Back in the day, it started off a trend of batteries in­cluded” tool­chains that give you a sin­gle, con­sis­tent in­ter­face for build­ing, test­ing, for­mat­ting, lint­ing, and man­ag­ing de­pen­den­cies. I’m glad that Rust fol­lowed suit, be­cause it’s a great model. It’s one of my fa­vorite parts about both ecosys­tems.

cargo has even more built-in:

The big dif­fer­ence is that in Go you typ­i­cally reach for third-party tools (golangci-lint, mock­gen, air, gore­leaser) to fill gaps. In Rust, the first-party ecosys­tem cov­ers more out of the box. Things that do re­quire ex­ter­nal crates (e.g. cargo watch, cargo nex­test) in­stall with one com­mand and feel na­tive, e.g. cargo in­stall cargo-nex­test gives you cargo nex­test right away.

Both com­mu­ni­ties have con­verged on the same in­sight about for­mat­ters: a sin­gle canon­i­cal style, even an im­per­fect one, is worth more than the bikeshed­ding it elim­i­nates.

Gofmt’s style is no one’s fa­vorite, yet gofmt is every­one’s fa­vorite. — Rob Pike, Go Proverbs

Gofmt’s style is no one’s fa­vorite, yet gofmt is every­one’s fa­vorite.

— Rob Pike, Go Proverbs

The same is true of rustfmt: not every­one likes every de­tail, but the ab­sence of style de­bates in code re­view is worth far more than the oc­ca­sional for­mat­ting pref­er­ence you’d have made dif­fer­ently.

Key Differences Between Go and Rust

The head­line is that Go and Rust are both com­piled, sta­t­i­cally typed, sin­gle-bi­nary-de­ploy lan­guages with strong con­cur­rency sto­ries. The dif­fer­ences are about what guar­an­tees you get from the com­piler and how much con­trol you have over run­time be­hav­iour.

One fram­ing that helps be­fore we go fur­ther: most of what changes when you move from Go to Rust is that checks get pulled into the type sys­tem. Nil-handling, er­ror prop­a­ga­tion, data races, re­source life­times, can­cel­la­tion, gener­ics, these are all things Go re­lies on con­ven­tion, tool­ing (go vet, er­rcheck, golangci-lint, -race), or run­time de­tec­tion to keep hon­est. Rust en­codes them as types the com­piler en­forces di­rectly.

The com­mon push­back is that this means more cog­ni­tive over­head.” I’d chal­lenge that. It’s more up­front, yes, but it’s also harder to hold wrong. A Mutex<T> in Rust does­n’t just doc­u­ment that the data needs a lock, it makes the lock the only way to reach the data: you call .lock(), you get a guard, and the guard is what gives you ac­cess to the in­ner value. Drop the guard and the lock re­leases au­to­mat­i­cally. There is no I for­got to lock” path be­cause the un­locked path does­n’t ex­ist in the type. Once you in­ter­nal­ize that pat­tern, and you find it re­peated every­where (Option, Result, &mut T, Send/Sync, RAII guards), Rust stops feel­ing heavy and starts feel­ing like the com­piler is do­ing work you used to do in your head.

Why Go Developers Consider Rust

Go de­vel­op­ers don’t usu­ally come to Rust be­cause Go is too slow.” For most back­end work­loads, Go is plenty fast. People are gen­er­ally a bit frus­trated with Go’s ver­bose er­ror han­dling, the dan­ger of seg­men­ta­tion faults from nil point­ers, and the lack of gener­ics (for a long time) or any so­phis­ti­cated type sys­tem fea­tures, such as enums or traits. Interfaces are not a wor­thy re­place­ment for traits, and the Go stan­dard li­brary has some weird gaps, such as the lack of a Set type. (The id­iomatic workaround is map[T]struct{}, which works fine in prac­tice but is a tell that the type sys­tem is­n’t quite car­ry­ing its weight.)

nil Panics in Production

You ship a Go ser­vice, it runs fine for months, and then a code path runs where some­one for­got to check whether a pointer was nil, and the gor­ou­tine pan­ics. A com­mon case is a lookup that re­turns the zero value, or a struct whose pointer fields sur­vived de­se­ri­al­iza­tion with­out be­ing pop­u­lated:

func (s *Service) Handle(req *Request) er­ror { // Find re­turns (*User, er­ror). The er­ror is nil for not found”; // the caller is ex­pected to check user != nil, but this is very easy to for­get. user, err := s.repo.Find(req.UserID) if err != nil { re­turn err } re­turn user.Ac­count.No­tify() // crashes if user is nil, or if Account is nil }

Linters and IDE checks catch some of these (nilaway, sta­t­ic­check), but they’re opt-in, prob­a­bilis­tic, and don’t cross pack­age bound­aries re­li­ably. Go’s com­piler it­self does not force you to con­sider the ab­sence case. Rust’s Option<T> does:

fn han­dle(&self, req: &Request) -> Result<(), ServiceError> { let user = self.repo.find(req.user_id)?; // re­turns Option<User>; ? short-cir­cuits None into an er­ror user.no­tify() }

You lit­er­ally can­not deref­er­ence an Option with­out ac­knowl­edg­ing the None case. Whole cat­e­gories of pager-duty in­ci­dents dis­ap­pear.

Data Races That -race Didn’t Catch

go test -race is a great tool, but it’s a run­time de­tec­tor, it only finds races that ac­tu­ally ex­e­cute dur­ing your tests. Mutating a map from two gor­ou­tines with­out a lock com­piles fine in Go and only blows up in pro­duc­tion un­der load.

In Rust, shar­ing mu­ta­ble state across threads re­quires types that im­ple­ment Send and Sync. Try to share a plain HashMap be­tween threads and the pro­gram does not com­pile. You’re forced to wrap it in an Arc<Mutex<…>>, an Arc<RwLock<…>>, or use a chan­nel. That race con­di­tion be­comes a type er­ror. 1

Paul Dix has been very can­did about what mo­ti­vated the InfluxDB 3.0 rewrite, and the data-race story is right at the top:

[The main ben­e­fit is] fear­less con­cur­rency — elim­i­nat­ing data races es­sen­tially, which we had be­fore. Really gnarly bugs in ver­sion 1 of Influx due to that. — Paul Dix, Founder & CTO, InfluxData, on Rust in Production

[The main ben­e­fit is] fear­less con­cur­rency — elim­i­nat­ing data races es­sen­tially, which we had be­fore. Really gnarly bugs in ver­sion 1 of Influx due to that.

— Paul Dix, Founder & CTO, InfluxData, on Rust in Production

Composable Error Handling

if err != nil { re­turn err } is fine for a while. After a few years, you no­tice three things:

The boil­er­plate di­lutes the ac­tual logic of your func­tion.

Wrapping with fmt.Er­rorf(“do­ing X: %w”, err) is a dis­ci­pline rule, not a com­piler rule. It’s easy to drop con­text on the floor.

Sentinel er­rors via er­rors.Is/​er­rors.As work, but the com­piler does­n’t tell you when you for­got to han­dle a new vari­ant.

It’s worth be­ing hon­est about the counter-ar­gu­ment here, since it came up in the Lobste.rs thread on my Shuttle ar­ti­cle: ex­pe­ri­enced Go de­vel­op­ers point out that er­rcheck and golangci-lint catch most of the forgot to han­dle the er­ror” cases in prac­tice, and that ex­plicit if err != nil is eas­ier to read than dense ? chains. Both points are fair, and the ex­plicit style is a de­lib­er­ate cul­tural value, not an ac­ci­dent:

I think that er­ror han­dling should be ex­plicit, this should be a core value of the lan­guage. — Peter Bourgon, GoTime #91, quoted in Dave Cheney’s Zen of Go

I think that er­ror han­dling should be ex­plicit, this should be a core value of the lan­guage.

— Peter Bourgon, GoTime #91, quoted in Dave Cheney’s Zen of Go

My take is that lints are an opt-in safety net you have to re­mem­ber to set up, while Rust’s Result<T, E> is the type sig­na­ture it­self, there’s no way to for­get. The boil­er­plate-vs-read­abil­ity trade­off is more gen­uinely sub­jec­tive.

In Rust:

#[derive(Debug, this­er­ror::Er­ror)] pub enum UserError { #[error(“user {0} not found”)] NotFound(UserId), #[error(“user al­ready ex­ists”)] AlreadyExists, #[error(transparent)] Repo(#[from] RepoError), }

pub fn re­name(id: UserId, name: &str) -> Result<User, UserError> { let mut user = repo::get(id)?; // ? con­verts RepoError -> UserError au­to­mat­i­cally user.name = name.to_string(); Ok(user) }

The ? op­er­a­tor han­dles prop­a­ga­tion; #[from] han­dles wrap­ping; and a match on UserError is ex­haus­tively checked. Add a new vari­ant to­mor­row and the com­piler shows you every place that needs up­dat­ing.

Generics That Don’t Box

Go got gener­ics in 1.18, and they’re use­ful, but the im­ple­men­ta­tion has con­straints (no meth­ods with type pa­ra­me­ters, GC shape sten­cil­ing, oc­ca­sional sur­pris­ing per­for­mance char­ac­ter­is­tics). Rust gener­ics monomor­phize, each in­stan­ti­a­tion pro­duces spe­cial­ized code with zero run­time cost. Combined with traits, this gives you real zero-cost ab­strac­tions.

This mat­ters less in han­dler code and more in shared in­fra­struc­ture (middleware, generic repos­i­to­ries, de­coders, parsers), where Go of­ten pushes you back to in­ter­face{}/​any plus type as­ser­tions.

Predictable Latency

Go’s GC is ex­cel­lent, con­cur­rent, low-pause, well-tuned for typ­i­cal ser­vice work­loads. But low-pause” is not no-pause.” Under heavy al­lo­ca­tion, P99 la­tency tails are no­tice­ably worse than a Rust equiv­a­lent that sim­ply does­n’t al­lo­cate on the hot path.

I won’t over­sell this, for the vast ma­jor­ity of ser­vices, Go’s GC is a non-is­sue. But for la­tency-sen­si­tive sys­tems (trading, real-time bid­ding, net­work prox­ies, high-through­put in­ges­tion), the lack of GC pauses is a gen­uine sell­ing point. Stephen Blum from PubNub put it di­rectly on the show:

Go is great at our scale, but we re­ally need some­thing that is go­ing to give us the price-per-dol­lar per­for­mance ca­pac­ity that we need, and Rust is go­ing to get us there. That’s why ba­si­cally every­thing is head­ing to­wards Rust these days. — Stephen Blum, CTO, PubNub, on Rust in Production

Go is great at our scale, but we re­ally need some­thing that is go­ing to give us the price-per-dol­lar per­for­mance ca­pac­ity that we need, and Rust is go­ing to get us there. That’s why ba­si­cally every­thing is head­ing to­wards Rust these days.

— Stephen Blum, CTO, PubNub, on Rust in Production

In Summary

Go is death by a thou­sand pa­per cuts. It is a very prag­matic lan­guage and if you are will­ing to glance over the above is­sues, you can be very pro­duc­tive in it. But at a cer­tain code­base size, the prob­lems start to com­pound. There is no sin­gle mo­ment when Go loses its ap­peal, but teams find them­selves wish­ing for more (more safety, more con­trol, more ex­pres­sive­ness) and that’s when they start look­ing around for al­ter­na­tives.

Comparing Both Languages Side by Side

The fastest way to feel com­fort­able in Rust is to map pat­terns you al­ready know. For a longer, fully-worked ex­am­ple of build­ing the same back­end ser­vice in both lan­guages, see the Shuttle com­par­i­son, the sec­tion be­low fo­cuses on the pat­terns that come up most of­ten.

Error Handling: if err != nil vs Result<T, E>

Go:

func ReadConfig(path string) (*Config, er­ror) { data, err := os.Read­File(path) if err != nil { re­turn nil, fmt.Er­rorf(“read­ing con­fig: %w”, err) } var cfg Config if err := json.Un­mar­shal(data, &cfg); err != nil { re­turn nil, fmt.Er­rorf(“pars­ing con­fig: %w”, err) } re­turn &cfg, nil }

Rust:

fn read­_­con­fig(path: &Path) -> Result<Config, ConfigError> { let data = fs::read­_­to_string(path)?; let cfg = serde_j­son::from_str(&data)?; Ok(cfg) }

The ? op­er­a­tor does the if err != nil { re­turn err } dance for you, in­clud­ing type con­ver­sion if From<E1> for E2 is im­ple­mented (idiomatic with this­er­ror’s #[from]).

Null: nil vs Option<T>

Go:

func GetUser(id string) *User { for _, u := range users { if u.ID == id { re­turn &u } } re­turn nil }

u := GetUser(“123”) fmt.Println(u.Name) // pan­ics if nil

Rust:

fn get_user(id: &str) -> Option<User> { users.iter().find(|u| u.id == id).cloned() }

let user = get_user(“123”); println!(“{}”, user.name); // com­pile er­ror: `user` is Option<User>, not User // You must han­dle both cases: match get_user(“123”) { Some(u) => println!(“{}”, u.name), None => println!(“not found”), }

There is no nil in safe Rust. References can’t be null. Pointers can be, but you al­most never use raw point­ers in ap­pli­ca­tion code.

Interfaces vs Traits

Go’s in­ter­faces are struc­tural, a type sat­is­fies an in­ter­face im­plic­itly:

type Reader in­ter­face { Read(p []byte) (n int, err er­ror) }

Rust’s traits are nom­i­nal, you im­ple­ment them ex­plic­itly:

pub trait Reader { fn read(&mut self, buf: &mut [u8]) -> std::io::Re­sult<usize>; }

impl Reader for MyType { fn read(&mut self, buf: &mut [u8]) -> std::io::Re­sult<usize> { /* … */ } }

The Go style is great for ad-hoc duck typ­ing. The Rust style is great for refac­tor­ing and dis­cov­er­abil­ity, you can grep for every im­ple­menter of a trait.

The clos­est equiv­a­lent of in­ter­face{} / any in Rust is Box<dyn Any>, but you al­most never want it. The Go com­mu­nity knows the cost of reach­ing for in­ter­face{} too:

in­ter­face{} says noth­ing. — Rob Pike, Go Proverbs

in­ter­face{} says noth­ing.

— Rob Pike, Go Proverbs

Generic func­tions with trait bounds (fn han­dle<R: Reader>(r: R)) cover the vast ma­jor­ity of cases and give you monomor­phiza­tion with no run­time dis­patch. Where Go pre-1.18 would have forced you back to in­ter­face{} plus a type as­ser­tion, Rust’s traits + gener­ics let you stay spe­cific.

When you do want run­time dis­patch (e.g. het­ero­ge­neous stor­age of dif­fer­ent im­ple­menters), reach for Box<dyn Trait> or Arc<dyn Trait>. That’s the di­rect Rust ana­log of hold­ing an in­ter­face value in Go.

Goroutines vs Async Tasks

Go’s con­cur­rency model is fa­mously sim­ple:

The Fragility of LLM Agents in Backend Code Generation

arxiv.org

Are you a robot?

www.bloomberg.com

Please make sure your browser sup­ports JavaScript and cook­ies and that you are not block­ing them from load­ing. For more in­for­ma­tion you can re­view our Terms of Service and Cookie Policy.

To add this web app to your iOS home screen tap the share button and select "Add to the Home Screen".

10HN is also available as an iOS App

If you visit 10HN only rarely, check out the the best articles from the past week.

Visit pancik.com for more.