Software Essays That Shaped Me
Posted3 months agoActive3 months ago
refactoringenglish.comTechstory
calmpositive
Debate
60/100
Software DevelopmentInfluential EssaysProgramming Principles
Key topics
Software Development
Influential Essays
Programming Principles
The post lists software essays that have shaped the author's perspective, sparking a discussion among commenters who share their own favorite influential essays and debate various programming principles.
Snapshot generated from the HN discussion
Discussion Activity
Active discussionFirst comment
9h
Peak period
16
12-18h
Avg / period
7.8
Comment distribution47 data points
Loading chart...
Based on 47 loaded comments
Key moments
- 01Story posted
Sep 30, 2025 at 10:01 AM EDT
3 months ago
Step 01 - 02First comment
Sep 30, 2025 at 7:30 PM EDT
9h after posting
Step 02 - 03Peak activity
16 comments in 12-18h
Hottest window of the conversation
Step 03 - 04Latest activity
Oct 2, 2025 at 4:17 PM EDT
3 months ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
ID: 45425568Type: storyLast synced: 11/20/2025, 6:45:47 PM
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
I disagree with "Don't put logic in tests", with the example provided being a problem with using strings where a URI type is needed instead. Perhaps the source of my disagreement is I hold that test code is production code due to test suite failure(s) during an automated build stops desired deployment.
Still, each are definitely worth delving into and determining applicability for oneself.
Yeah, I find it so baffling that 90% of programmers I talk to have never heard of it. My circle is more Go/Python/C++ folks, so maybe it's more well-known in functional programming circles.
>I disagree with "Don't put logic in tests", with the example provided being a problem with using strings where a URI type is needed instead. Perhaps the source of my disagreement is I hold that test code is production code due to test suite failure(s) during an automated build stops desired deployment.
Yeah, I think that's a fair criticism. I think the specifics of the example could be better, but I think the important underlying message is that even something that seems simple like a string concatenation is added complexity that can mask a bug in a test.
> Yeah, I think that's a fair criticism. I think the specifics of the example could be better, but I think the important underlying message is that even something that seems simple like a string concatenation is added complexity that can mask a bug in a test.
I didn't mean to criticize so much as identify why I consider test code to be the same as production code.
Continuing with the example provided, the string concatenation is not the problem this test identifies IMHO. Instead, it is that:
Returns a `String` instead of a type which disallows the formulation of the problematic `assertEquals` to begin with.In a more general sense, I have found treating test suites the same as one would production code (refactoring, commenting, sometimes testing support logic used to define tests, etc.) has led to tests benefiting the same way. This approach also has had a twofold benefit of "keeping the same energy" when producing all source artifacts along with serving as a great way to onboard new team members.
All the usual caveats apply, of course. YMMV, IMHO, etc. :-)
I'm not sure what the best attribution would be but "Make illegal states unrepresentable" would be a fantastic addition to this list pairing well with "parse, don't validate".
A stricter type would force you to parse the URL and would either fix the error (because cleaning trailing/leading slashes might make sense here) or throw a clear error from the parser.
It can be slightly more verbose when you just want to write a string in your test for convenience but can (and does) save a lot of debugging pain for less trivial cases.
> I'm not sure what the best attribution would be but "Make illegal states unrepresentable" would be a fantastic addition to this list pairing well with "parse, don't validate".
The phrases I have seen describing using types to make illegal states incapable of being represented are "programming with types"[0] and "type level programming"[1].
HTH
0 - https://www.manning.com/books/programming-with-types
1 - https://rebeccaskinner.net/posts/2021-08-25-introduction-to-...
Ideally a test should be an extremely literal interpretation of the spec. The test in the example I would read as "the output should be the result of a string concatenation between the base URL string and this string". The problem is that spec doesn't exist because it's stupid and wrong. This test suite implements a bug-ridden, ad hoc URL builder.
The real spec is probably "the output should be a string containing a valid URL for the photos page". I see two options for writing this test:
1. Compare to a "trusted" string literal which conforms to the spec (ie. to be a valid URL for the photos page),
2. Decode the string using a "trusted" URL decoder and validate it at the URL level.
I think they are equally valid options and a matter of taste and convenience but both accurately reflect the spec, unlike the example.
The second option is essentially playing off two bits of code against each other, like testing a forwards operation against a reverse operation. This works if both bits of code are completely independent and therefore extremely unlikely to accidentally compensate for each other's bugs. If the URL decoder is in a widely used standard library then this could be considered OK (the robustness principle explicitly makes things asymmetric, though, so a URL decoder with a "strict" mode would be most appropriate). But ad hoc code written in a test suite is definitely not OK!
To be fair, it doesn't happen often, though what I'm seeing more of is just blatantly bad tests written by LLMs. It's hard to blame a philosophy when dealing with humans that have fully delegated their brains over to a random number generator.
I agree that there is a balance to be had here. The "logic in tests" I imply is logic which should only exist to make test suites have all of the "ables" we want in production code; extensible, readable, maintainable, understandable, etc. And when I do think "tests for tests" are applicable it is not for the tests themselves, but for the rare cases of supporting logic pervasive in non-trivial test suites.
> To be fair, it doesn't happen often, though what I'm seeing more of is just blatantly bad tests written by LLMs. It's hard to blame a philosophy when dealing with humans that have fully delegated their brains over to a random number generator.
I can't agree with you more on this.
Bad code (test or otherwise) generated by LLM's does not make clueless people more productive. It just pushes crap upstream for someone else to deal with.
McConnell isn't especially popular, hereabouts, though.
I was wondering whatever happened to him because the guys that were popular around his time (Kent Beck, Martin Fowler, Ward Cunningham) all continued writing, even if their popularity waned after the 2000s. But I just never saw anything from McConnell again.
It turns out he quit software to be a financial advisor, which is quite surprising.[0]
[0] https://raindogllc.com/steve-mcconnell-investment-advisor/
I think he made a pile of money, somehow, and does what he wants.
He did a whole bunch of data-mining around COVID: https://stevemcconnell.com/cdc-covid-19-forecast-evaluations...
https://grugbrain.dev/
I don’t understand what « grug » is supposed to mean for example.
That being said I still enjoy the blog.
For whatever reason, the sound "Grug" is associated with cavepeople in English.
[1]: https://en.wikipedia.org/wiki/The_Croods
Meant to be some generic "caveman" name/character.
grug neighbours ugg, oog, thog, thag, tragg, yog, grr, argh not use computer
https://tvtropes.org/pmwiki/pmwiki.php/Main/HulkSpeak
> grug quite satisfied when complexity demon trapped properly in crystal, is best feeling to trap mortal enemy!
Like, I've heard "no silver bullet" quoted enough that I could write about the main ideas, despite never having read the paper.
> In the boring analogue world - I am pretty sure that I'd be able to convince a human that I am who I say I am. And, thus, get access to my accounts. I may have to go to court to force a company to give me access back, but it is possible.
> But when things are secured by an unassailable algorithm - I am out of luck. No amount of pleading will let me without the correct credentials. The company which provides my password manager simply doesn't have access to my passwords. There is no-one to convince. Code is law.
Everyone should understand this problem before they advocate to remove the in-person version of a process. The article's example sounds unlikely at first, but the same consequences can happen with any natural disaster or a robbery.
[1] https://shkspr.mobi/blog/2022/06/ive-locked-myself-out-of-my...
https://c00kiemon5ter.github.io/code/philosophy/2011/10/30/T...
This is about as incorrect as it gets.
The only way to verify correctness is to change the production code in a way that should cause the test to fail, then watch it fail. In TDD this is done by writing the test before you write the code that would make it pass, then watch it fail. Only then are you allowed to write the code that makes it pass.
Otherwise you have no proof the test can EVER fail - which means no proof it adds value to your codebase.
>This is about as incorrect as it gets.
>The only way to verify correctness is to change the production code in a way that should cause the test to fail, then watch it fail. In TDD this is done by writing the test before you write the code that would make it pass, then watch it fail. Only then are you allowed to write the code that makes it pass.
>Otherwise you have no proof the test can EVER fail - which means no proof it adds value to your codebase.
I agree that changing the production code to cause a failure can be helpful, but I think it's an overstatement to call it "the only way to verify correctness." When I optimize for simplicity, I rarely encounter tests that pass in situations I didn't expect.
Also, forcing tests to fail doesn't really scale. You can do it initially as you write a new function, but once you commit your changes, whatever you've learned from the exercise evaporates. If you change the function or any of its dependencies, presumably you're not going to repeat the exercise of forcing each assert to fail one-by-one. According to what you're saying, that means that there's no longer proof that the test can fail.
> Modern AI has thrown a wrench into Brooks’ theory, as it actually does reduce essential complexity. You can hand AI an incomplete or contradictory specification, and the AI will fill in the gaps by cribbing from similar specifications.
The essential part is still not adequately covered by Generative AI, and probably never will be. Here is my detailed write-up about it: https://smartmic.bearblog.dev/no-ai-silver-bullet/
It's like putting on an exo suit, lifting something very heavy and putting it on a shelf, then asking your teammate to go paint it.
In your writeup, it seems like you're arguing that LLMs can't eliminate essential complexity, and I agree that they probably can't.
But I do think they can reduce essential complexity.
As a concrete example, here's me prompting Claude 4.1 Opus to define a domain-specific language for creating computer-generated paintings.[0] I just provided the requirements and left a lot of ambiguity in the specifics.
In that example, has LLM reduced essential complexity at all?
To me, the answer is clearly yes. It wrote a spec based on my requirements. I could potentially do better if I defined it from scratch, but if the LLM-generated spec is good enough, then it likely isn't worth the cost of me doing it myself for the marginal improvement in quality.
When LLMs first came out, I felt like I had no need for them because I think I can write code better than they can, and I enjoy writing code. But as I've started experimenting with them, I'm realizing that there are some problems that I can solve with software that I don't actually enjoy implementing and I don't care that much about specifying every aspect of my program's behavior, so LLMs fit well in those situations and eliminate essential complexity that would otherwise fall in my lap.
[0] https://kagi.com/assistant/1b8324a2-ae54-4a1b-9c69-51d76fc5c...
0: https://caseymuratori.com/blog_0015
* An Investigation of the Therac-25 Accidents
https://cse.msu.edu/~cse470/Public/Handouts/Therac/Therac_1....
* The Therac-25: 30 Years Later
https://ieeexplore.ieee.org/document/8102762
2. Charles Fishman's They Write the Right Stuff
https://www.eng.auburn.edu/~kchang/comp6710/readings/They%20...
Changed the way I think software.
https://prog21.dadgum.com/21.html
He talks about how imports and exports are global state, and that they have all the issues that global state brings. It's made me appreciate dependency injection a lot more.
https://mahesh-hegde.github.io/readings/
https://www.kalzumeus.com/2011/10/28/dont-call-yourself-a-pr...