Hacker News new | past | comments | ask | show | jobs | submit login

I've enjoyed both books but Uncle Bob is something you grow out of. He was a bit of a cult figure at the time. Trying to actually follow the guidelines in Clean Code taught me a lot about "over-decomposition" and, ultimately, how not to write code. It reminds me it's possible to take aesthetics so far the results become ugly. Fussing over a proliferation of small functions that do only one thing is a kind of madness. Each individual function eventually does zero things. You are left sifting through the ashes of your program wondering "Where did I go wrong?"

On the meta level, these exchanges, while mildly interesting, have the vibe of debating how many angels can dance on the head of a pin. I'm reminded of the old saying: "Writing about music is like dancing about architecture." If you want to write good code, read good code. Develop a taste that makes sense to you. I don't think I'll ever read a book about code composition again.




> If you want to write good code, read good code.

As a junior in the field working at a small company, I often rely on this community for guidance, and this seems the most sound advice on this thread.


You need to know what is good code. Opinions may vary a lot between programmers, even senior ones. The Clean Code cult would tell you to find good code there but that is the most poisonous programming book I have read.


Forget about the code itself and focus on the results.

What I mean by that: Good code is code that has proven itself by surviving quietly in a long-living project that has changed a lot over many cycles of new engineers (experienced or otherwise) being onboarded. The less you hear people complain about it but the more you find people using or relying on it in some way, the better the code. If people are loud about how much they like it, it’s either new, or it’s something they’ve convinced themselves to like but know in their hearts is bad. It’s the stuff that just works that’s good - it’s so good people don’t even notice it.


No, because then you end up reading old C-code that are IFDEF mazes and think that is good code. No, to see good code you usually have to look at what experienced people write when they get to greenfield something new.


So you think code that is ugly is bad code? Or is it that it uses janky/outdated features? What makes it good if not its lifetime value?

Surely you don’t just presume the quality of code based on the person who wrote the code, right?


What makes it good is the tradeoff between how well it solves the problem compared to how easy it is to maintain. And people learn how to write better code as they get more experienced, but old projects are seldom rewritten using the learnings - it is often just easier to start over from scratch.


You have to read a lot of different code. Everyone thinks their code is good when they write it. Often old ugly code has a beautiful design still hidden behind many many requirements changes that didn't fit with the original design. Other code looks nice and beautiful but it will stand the test of requirement changes even worse than the other.


> Forget about the code itself and focus on the results.

This reminds me of what Dijkstra said (paraphrasing): the computation is the important thing, not the code.


Not really, long-living projects don't adapt their complete code base with gained experience, much like the Linux Kernel probably will never be rewritten in Rust, C++ projects never transformed to C++14+, etc.


The interesting thing to look for here is the parts of the codebase that don't need to adapt with gained experience. That's the key. If people aren't changing it, they haven't needed to, and that's a useful signal.

Conversely, looking for the parts of a codebase with the highest churn will tell you immediately what all the devs on that codebase will complain about, if you ask them. This has worked for me extremely well across a number of projects.


It can also mean "We have not changed this because we don't dare to do that, or it is too much work and we just have to live with the bad decisions made 25 years ago". And that is the last code you want to copy.


It is, but those cases tend to be obvious.


It’s interesting that we just assume a newer language produces “better code”


there are lots of very robust programs in various languages to learn from. It would be hard to know in isolation but by contrast it is easier to learn what good code looks like. Some code will flow and be easy to read. Other code will be obtuse. Start with simpler projects that don't involve a lot of low-level calls. Work up to more complex implementations. There was never a better time to read code than now with an LLM as a tutor. If you use one of the AI-integrated editors or a code packer you can provide a lot of context to the LLM. Ask the LLM for important modules and work your way through them. Ask it for alternative implementations of a function or translated into a different language. Set up an program in a running environment and walk through using a debugger. Look at the way the code is organized in files and modules. You will inevitably encounter cruft and "bad code". Sometimes there are good reasons for that too. If you prefer books, the Architectures of Open Source Applications (AOSA) books are interesting, but there really isn't a way to avoid pulling down a repo and reading the code. Soon, you'll develop your own taste for what makes sense to you and be able to think independently about the choices the developer made.

It is a bit sad but I think with the advent of LLMs some of the stylistic quirks of programmers past will become a bit anachronistic. Still, they will present opportunities for code archeology.


Just a point here, "good code" is sometimes subjective, and depends on understanding the context of what the code is doing. What you think is good code might be overly verbose to another person, or overly terse, or have poorly named variables, or not have sufficiently conservative guard clauses, or throw insufficiently-granular exceptions. What you think is confusing code might lack context for where it is in the stack and what problems it needs to solve at that layer of the stack.

You can also read critical reviews of someone else's work, compare them with the work in question, and see if the critic's punches land or if they look like misses.

https://qntm.org/clean

^ This, I thought, was a good takedown of Clean Code, highlighting some cases where Bob Martin made too many overly thin functions that lacked meat and made it hard for the reader to gain context for what the function was trying to do. [1]

I would also say, reading "the same code" in different programming languages might get you a feel for if you prefer code to be more verbose or more terse, more explicit or more implicit. e.g. https://rosettacode.org/wiki/Globally_replace_text_in_severa...

[1] sometimes derisively referred to as "lasagna code" or "baklava code" -- https://www.johndcook.com/blog/2009/07/27/baklav-code/


Agreed.

Some other heuristics:

* Every if statement is a chance of a bug because the code has two or more paths to follow. Keep the choice making at the business/requirements level of the code, not hidden inside lower level decomposition.

* A switch statement that is not exhaustive (ie covers all possible values) is a change of a bug, especially if there is no default case.

Modern languages with better type systems make the second point less relevant because they require exhaustive pattern matching.


Every if statement is a chance of a bug because the code has two or more paths to follow

This is known as the cyclomatic complexity of a program: https://en.wikipedia.org/wiki/Cyclomatic_complexity

A corollary to this is that it is also beneficial to converge separate paths as quickly as possible (e.g. using non-nullable types and default values) or converge them all to the same place (e.g. nonlocal exception handling).


I often abbreviate that to "Psychosomatic Complexity" because more complex code is likely to give the programmer a headache.


> You are left sifting through the ashes of your program wondering "Where did I go wrong?"

Brilliantly phrased metaphor, thank you.


>Each individual function eventually does zero things.

Lambda calculus, basically :)


it has been years since I read the book, but I'm surprised that there's so much hatred for it here. From memory it seemed like fairly harmless things like give things good names, try to make the code readable, dont comment what the code does but why, use consistent formatting, avoid duplication.

Other than people going overboard with empty classes and inheritance Ive not really seen a problem of people breaking down functions too far.

Which parts are important to grow out of?


There’s a good overview of the faults of Clean Code at https://qntm.org/clean.


Please read it again, you might see it differently now.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: