August 5th, 2024

How I Program in 2024

Kartik Agaram reflects on his programming journey, advocating for minimalist software design, emphasizing simplicity, context awareness, and the potential benefits of data-oriented design to improve software quality and adaptability.

Read original articleLink Icon
FrustrationSkepticismCuriosity
How I Program in 2024

In 2024, Kartik Agaram reflects on his programming journey, emphasizing the importance of building trustworthy software infrastructure. He discusses his experiences with the Mu platform and Freewheeling Apps, noting a shift in his approach to programming over the years. Initially, he prioritized tests and version control, believing they were essential for quality software. However, after a month of reworking his text editor, he deleted all tests and found that this radical change led to a better program. Agaram concludes that building durable software for a broad audience is challenging and suggests focusing on simpler, less commercialized software with fewer dependencies. He highlights the impact of context on software design and the tendency of existing software to become overly complex due to short-term incentives. Agaram advocates for a minimalist approach to programming tools, warning against over-reliance on abstractions and tests, which can complicate software unnecessarily. He proposes that when understanding of a program's context stabilizes, it may be beneficial to discard large portions of the code and start anew. He also introduces the concept of data-oriented design as a valuable perspective for improving software. Agaram acknowledges that his programming has evolved since his last reflections in 2019 and expresses curiosity about future developments in his approach. Overall, he emphasizes the need for thoughtful programming practices that prioritize clarity and adaptability over complexity.

AI: What people are saying
The comments on Kartik Agaram's article reflect a mix of opinions on minimalist software design and the abandonment of tests and version control.
  • Many commenters emphasize the importance of testing and version control, arguing that they are essential for maintaining software quality and collaboration.
  • Some express skepticism about the author's approach, suggesting that it may work for individual projects but is not scalable for team environments.
  • There is a recognition of the trade-offs between simplicity and the potential risks of not using established practices like testing.
  • Several comments highlight the subjective nature of programming practices, with some supporting experimentation while others advocate for traditional methods.
  • Common frustrations with testing and version control are noted, indicating that while they can be burdensome, they ultimately serve important functions in software development.
Link Icon 39 comments
By @aetherspawn - 2 months
When you have no tests your problems go away because you don’t see any test failures.

Never have I tested anything and NOT found a bug, and most things I tested I thought were already OK to ship.

Thus, when you delete your tests, the only person you are fooling is probably yourself :(

From reading your page I get the impression you are more burnt out from variation/configuration management which is completely relatable… I am too. This is a hard problem. But user volume is required to make $$. If the problem was easy then the market would be saturated with one size fits all solutions for everything.

By @munchler - 2 months
> Giving up tests and versions, I ended up with a much better program.

I can’t understand how anyone would willingly program without using source code control in 2024. Even on a single-person project, the ability to work on multiple machines, view history, rollback, branch, etc. is extremely valuable, and costs almost nothing.

Maybe I’m misunderstanding what the author means by “versions”?

By @shepherdjerred - 2 months
At first glance I thought the author was plain wrong, but I think there is some good insight here.

This workflow works very well for the author. Most of us can probably think of a time when Git or automated tests frustrated us or made us less productive. There are similar solutions that are simpler and get out of the way, e.g. backing up code with Dropbox, FTP, whatever.

The above is works well because the author is optimizing for their productivity on a passion project where they collaborate with few others.

Automated tests are useful, but it sounds like the author likes creating programs so small that the value might not surface. I think that automated tests still have value even in this context, but I think we can all agree that automated tests slow you down (though many would argue that you see eventual returns).

Version control and automated tests solve real problems. It would be insane to start a project without VC today, and automated tests are a best practice for a reason. But, for the authors particular use case, this sounds reasonable.

---

Aside from the controversial bits around VC/tests, I think items 7/8/9 perfectly capture my mindset when writing/refactoring a large program. Write, throw it away, write again.

By @layer8 - 2 months
This is quite a confused article.

I really wonder what about it made it be upvoted to first place.

By @AdieuToLogic - 2 months
> In 2022 I started working on Freewheeling Apps. I started out with no tests, got frustrated at some point and wrote thorough tests for a core piece, the text editor.

This is a primary motivation for having a reasonable test suite - limiting frustration. Test suites gives developers confidence to evolve a system. When done properly, contributors often form an opinion similar to:

> But I struggled to find ways to test the rest, and also found I was getting by fine anyway.

This is also a common situation. As functional complexity increases, the difficulty to test components or the system as a whole can become prohibitive.

> Now it's 2024, and a month ago I deleted all my tests. ... In effect I stopped thinking about version control. Giving up tests and versions, I ended up with a much better program.

This philosophy does not scale beyond one person and said person having recent, intimate, memory of all decisions encoded in source code (current or historical). Furthermore, given intimate implementation knowledge, verifying any change by definition must be performed manually.

By @pmontra - 2 months
My favorite example for point number 3 "Small changes in context (people/places/features you want to support) often radically change how well a program fits its context." is K9 Mail, which is becoming the Android version of Thurderbird now.

It started with an unconventional UI with a home page listing email accounts and for each account the number of unread and total messages. There was a unified inbox but it was not forced on users.

I remember that I explicitly selected this app because it fit my needs: one personal account, one work account, several work accounts that my customers gave me. I wanted those account to stay separated.

Probably a lot of K9 users picked that app precisely for the same reason because there were many complaints when the developer migrated to a conventional Android UI with a list of accounts sliding from the left and an extra tap to move from an account to another. If we had liked that kind of UI chances are that we won't have picked K9 to start with.

So one small change (but probably a lot of coding) destroyed the fitness of the app to its users. I keep using the old 5.600 version, the latest with the old UI, and I sideload it to any new device I buy.

Furthermore, to make things even more unusual, I only use POP3 to access my accounts (I preview on phone, delete stuff, possibly reply BCCing myself, eventually download on my laptop) and K9 fit perfectly that workflow. I don't need anything fancy. An app from the 90's would be good enough for me.

By @codr7 - 2 months
I too keep wondering where this path leads.

One thing is clear to me though, creating (software) by yourself is a completely different activity from doing it in a team.

About testing. Tests are means, not ends. What we're looking for is confidence I think. So when I feel confident about an implementation, I'll test less. And if I desperately need to make sure something keeps working, I'll add a few integration tests at the outer edges that are not so affected by refactorings and thus won't slow me down as much. E.g poking a web backend from the outside, as opposed to testing the internals. Unit tests are good for fleshing out the design of new API's, but those tests are pretty much useless once you know where you're going.

By @hiAndrewQuinn - 2 months
Just dropping by to say I adore this author and Mu is one of my favorite projects. A modern Lisp machine, kinda! In QEMU! So much fun!
By @huijzer - 2 months
> Most software out there is incurably infected by incentives to serve lots of people in the short term.

Great quote! You can even replace “software” with “businesses” and the quote still works.

By @alentred - 2 months
We are all a bit overwhelmed by the complexity of the field of software engineering. Arguably sometimes accidental. But I don't agree that rejecting all the ideas we have come up with over the decades is a solution. On the other hand, not all solutions should be taken to the letter or used "too much". "Overwhelming" is by definition what happens when something is used "too much". By all means, please, write tests, use the VCS, use abstractions, but *know why you use them*, and when the "why" doesn't hold - reassess.
By @brokegrammer - 2 months
There are some interesting ideas in this article. Not using source control and removing tests resulting in a better program is quite fascinating.

It's a shame that there are so many rude comments. It seems like there are many close minded folks lurking here, forgetting that experimentation is essential in tech.

By @GTP - 2 months
I don't agree with point 3:

"Small changes in context (people/places/features you want to support) often radically change how well a program fits its context. Our dominant milieu of short-termism doesn't prepare us for this fact."

My opinion here is that short-termism is precisely a consequence of the hardness of predicting/keeping up with these small changes: businesses prefer to be able to adapt quickly to new scenarios rather than risking being stuck in the wrong direction.

By @mattlondon - 2 months
I have noticed a few articles recently on HN that talks about dropping tests because they are too slow or holding them back or just extra cognitive load.

This kinda beggars belief for me. I wonder who these people are - do they have the "battle scars" from working on complex or big systems? Are they reasonably junior or new to the profession with less than 10 years experience?

Next up? Fuck structural engineers, it's just going to slow us down building this bridge...

If you are doing something for fun, sure do whatever you want. I write zero tests for my own pet projects. But please in professional environments please don't ignore hard-won lessons in reliability and engineering-velocity because you don't want to have to do the extra work to update your tests. Your customers and colleagues (potentially years in the future) will thank you.

By @ggm - 2 months
There is a class of problem where you know the goal, and code which produces the goal which you can test independently is demonstrably ok. Of course the next run with different parameters may well be wrong, but if they aren't on the goal-path you don't much have to worry.

I do sometimes code in this pattern. I have high confidence in charts from Google and Akamai about some data I have exposure to (a variant of the inputs unique to my situation not in their hands) and when the curves I make conform in general trend to the ones they make over the time series, I am pretty sure I have this right. If the critique is in the fine differences I do some differential on it. If the critique is in the overall shape of the curve, if mine is like theirs, why do you think I am so wrong?

By @ashishb - 2 months
I love end to end tests even for personal projects https://ashishb.net/all/bad-and-good-ways-to-write-automated...
By @xelxebar - 2 months
Data-orientation, abstraction avoidance, holistic rewrites. The values espoused by OP rhyme heavily with the stance I've begun to take after reading and writing significant amounts of APL.

The best code I've seen mercilessly elides anything that doesn't serve an architectural level, problem domain-relevant concern. GADTs and hash tables, and all our nice CS tools work much better when applied as cognitive tools in a domain-specific manner as opposed to reified language syntax or library APIs, as the latter necessarily introduces cross-domain concerns and commensurate incidental complexity.

The most blatant example of this in APL is using arrays and tables for everything. Trees? Can be efficiently encoded as arrays. Hash tables? Same. Tuples? Just a pair of vectors. Etc. APL's syntax really shines in this instance, since data interaction patterns become short, pithy APL expressions instead of zoos of library functions. Using direct expressions makes specialization much easier, by simply ignoring irrelevant concerns.

Anyway, APL aside, I'd really like to see our software engineering zeitgeist move more toward an optimistic refining our understanding of the human practice of software engineering and away from pessimistic and programming-centric problem avoidance.

(The above really came out more treatisy than intended. Oh well.)

By @slowmovintarget - 2 months
Can I just say... I love the return of the term "programming," "to program," and "programmer." "Coder" and "coding" was popular for a while, and before Steve Balmer put his stamp on it, "developers" and "development." But when I started, before 32-bit Windows was a thing, I was a programmer.

If the Primeagen has helped popularize the term again, great, thank you.

By @_gabe_ - 2 months
I can sympathize with the authors love/hate relationship with tests, but I can’t help feeling like it’s because we as developers so often test the completely wrong things.

I don’t typically write tests, but they do make sense for a few cases (specifically end to end tests that look for well defined outputs from well defined inputs). I was inspired by Andreas Kling’s method of testing Ladybird, where he would find visual bugs, recreate the bug in a minimum reproducible example, fix the bug, then codify the example into a test and make sure the regression was captured in his test suite[0]. This led to a seemingly large suite of tests that enabled him to continue modifying the browser without fear of regressing somewhere.

I used this method of testing while I was writing a code highlighter that used TextMate grammars. Since TextMate grammars have a well defined output for some input of code + grammar, I was able to mimic that output in my own code highlighter and then compare it to TextMate’s output for testing purposes. I wrote a bunch of general purpose tests, then ran into a bunch of bugs where I would have mismatched output. As I fixed those bugs, I would add the examples to my test suite.

Anyways, my code highlighter was slow, and I wanted to re-architect it to speed it up. I was able to completely change the way it worked with complete confidence. I had broken tests for a while in the middle of the refactor, but eventually I finished the refactor. As I started to fix the broken tests, there was a domino effect. I only had to fix a few tests and that ended up automatically correcting the rest. Now, I have a fast code highlighter and confidence that it’s at least bug for bug parity with the slow version :)

[0]: https://youtu.be/W4SxKWwFhA0?si=PJs_7drb3zVxq0ub

By @miffy900 - 2 months
> Giving up tests and versions, I ended up with a much better program.

This is one of those sentences that is clearly an opinion but stated as if it were some undeniable, incontrovertibly true statement of fact.

In your opinion, you have a better program - but give the code or repository to another dev or a group of devs and I'm sure you'll hear very different things...

By @hellectronic - 2 months
IMHO there are tests and there are tests. I had to work with codebases that had awful tests. They broke frequently because they were badly written. They used a lot of mocking when mocking was not appropriate. This tests were written for the purpose to have tests not for the purpose to really test the domain. I do not write tests for simple cases, like method in class A just delegates to method in class B.

For a one man show - go on do not write tests, especially if you do not know where you will end up with the software. But in teams I find a lot of value in (good written) tests, preventing bugs and documenting bugs. Sure you can over-engineer it, as everything else too.

BUT working without version control? Good that it works for you. I think version control is one of the MUST USE tools.

By @richrichie - 2 months
> Building durably for lots of people is too hard, just don't even try. Be ruled by what you know well, who you know well and Dunbar's number.

Wikipedia on Dubar:

> A replication of Dunbar's analysis on updated complementary datasets using different comparative phylogenetic methods yielded wildly different numbers. Bayesian and generalized least-squares phylogenetic methods generated approximations of average group sizes between 69–109 and 16–42, respectively. However, enormous 95% confidence intervals (4–520 and 2–336, respectively) implied that specifying any one number is futile.

https://en.m.wikipedia.org/wiki/Dunbar%27s_number

By @SethMurphy - 2 months
I have always found integration tests most important in order to test business logic when your customers pay for your trust and especially when they rely on your code for revenue while interacting with a third party. However, they should be thrown away immediately after proving your coded logic matches business requirements as they are slow and lose value and become tech debt quickly. Unit tests, if needed, should be even more temporary in my opinion. Often a CLI can be sufficient as a "unit test" during the development process.
By @skybrian - 2 months
> Small changes in context (people/places/features you want to support) often radically change how well a program fits its context. Our dominant milieu of short-termism doesn't prepare us for this fact.

I'm wondering what would work better? Writing a small program from scratch, using a rich ecosystem of libraries, seems like one way to go. AI help makes that easier.

Another approach, more common with popular apps that have more to lose, is to evolve in place.

By @zombiwoof - 2 months
I worked with a guy who was so obsessed with testing he never even bothered to ask what the feature or problem the code was to solved

He happily and condescendingly told every else how much they sucked because he had 1000% test coverage

When he released he had tons of bugs because his code wasn’t going what it was supposed to

His answer: yelling at product and tech leads for not being clear

The rest of us had tests but spent as much time asking clarifying questions

The guy above is one of the reasons I just lost all interest in software. This was a major FAANG company and his smooth talking continues today with management none the wiser because “he has the tests” Arby’s

By @irjustin - 2 months
I appreciate the honest answers by the OP. Even if we all think there's fundamental flaws with what was given up.

For me, ChatGPT saved a lot of my mental load. I don't think about individual lines NEARLY as much. Obviously you need to understand what the program is doing and be smart about it, but you can really focus on business problems.

It spits out something like 40% of my code and 70% of tests. I've started dropping whole files into it and tell it how to combine a new code.

By @ein0p - 2 months
If you don’t have tests you don’t know if your shit works, and your team size can be at most 1. I even write broad coverage tests in my private repo to have a modicum of assurance that when I change things the remaining code still works.
By @behnamoh - 2 months
> Types, abstractions, tests, versions, state machines, immutability, formal analysis, all these are tools available to us in unfamiliar terrain. Use them to taste.

How did people program in Lisp for decades? I like types and such, and have even gone so far as to write Python like it's Rust. But in the end I realized dynamic languages have an appeal for a reason, and by using types all over the place, I was not getting the benefits of a dynamic language like Python.

When context is mostly static, dynamic languages shine. Context could be, for example, the structure of the directory. If I want to read a file and I know that the file exists, throwing a bunch of type checks about file reading operation is just overkill and slows down the development.

By @0x008 - 2 months
this article must be written with the intention to troll HN
By @arendtio - 2 months
My approach to programming in 2024 is a bit different: When I want to code a new module, I start by talking to an AI about the requirements and let the AI generate the tests and the code.

Sadly, the AI isn't capable of generating working code for all scenarios, so eventually, I take over the code and finish/fix it.

The workflow itself can be quite frustrating (who doesn't love fixing bugs in other people's code?), and the act of coding isn't as much fun as it used to be, but the AI also shows me new algorithms, which is a great way of learning new things.

Let's just say I am looking forward to 2025 ;-)

By @ramzez - 2 months
The author should really setup SSL on his website and make it secure to browse to begin with.
By @nickelpro - 2 months
Insanity-grade takes end-to-end, not a single word of this should be taken seriously
By @andrewstuart - 2 months
If you are writing tests but have no users then you are wasting your time and money.
By @curry798 - 2 months
Is it recommended to learn shell if you are a beginner?
By @Jerry2 - 2 months
I wish someone would share their programming workflow when using LLMs... I feel like I'm falling behind in this area.
By @shove - 2 months
I’m really curious whether my agree:disagree ratio will be higher in the article or in the comments.