Live data from Hacker News

"Clean" Code, Horrible Performance (2023)

computerenhance.com

61–70 of 192 posts

Re: "Clean" Code, Horrible Performance (2023)

#61

I consider Clean Code to be in the category of books/styles that is helpful for early developers who need some structure, but harmful to late-stage developers who adopt it as dogma. On a long enough career path, eventually you will run into one Clean Code zealot who carries an air of superiority and nit picks every PR over things like a function having more than an arbitrary number of lines in it instead of reviewing…

My personal benchmark for 'maybe this function is too long' is when it doesn't fit on the page.

I don't think any such benchmark should exist. As long as the function only does one thing there is no upper limit. Artificially splitting a large function only reduces readsbility. What would you name the parts? do_stuff1(), do_stuff2(), do_stuff3()?

I have seen very clean codebases with a handful very long functions, but they were no issue she nice they only did one thing.

I personally write quite short functions but I have never understood why people take issue with large functions. Those are one of the easiest things to fix in a bad codebase. It is much harder to clean up after someone who used too small functions.

Re: "Clean" Code, Horrible Performance (2023)

#62

I consider Clean Code to be in the category of books/styles that is helpful for early developers who need some structure, but harmful to late-stage developers who adopt it as dogma. On a long enough career path, eventually you will run into one Clean Code zealot who carries an air of superiority and nit picks every PR over things like a function having more than an arbitrary number of lines in it instead of reviewing…

The function size is one rule from Clean Code I disagree with, it's silly. I love helper methods, but use them to a reasonable standard. I'd argue, if you cannot see it all on a 1080p monitor, that it might be getting a bit too long. I read PEP-8 religiously before I learned about "Clean Code" and it helped me to have sane standards in general. Methods that are roughly under 100 lines of code are okay, better is to fit it all in your monitor, 1080p being probably the most common resolution that leaves you with roughly 50 to 60 lines of code. If you have to scroll, you might want to consider helper functions to simplify and shorten logic.

Functions always being under 10 lines just means you've got functions everywhere, which can be mentally exhausting to follow logic, if you aim for like 40 lines tops you can write better "stories" with your code that are easier to follow and more expressive.

Re: "Clean" Code, Horrible Performance (2023)

#63

I consider Clean Code to be in the category of books/styles that is helpful for early developers who need some structure, but harmful to late-stage developers who adopt it as dogma. On a long enough career path, eventually you will run into one Clean Code zealot who carries an air of superiority and nit picks every PR over things like a function having more than an arbitrary number of lines in it instead of reviewing…

> I consider Clean Code to be in the category of books/styles that is helpful for early developers who need some structure

Clean Code is unhelpful to beginners too, though: misuse of industry-standard terms, shunning of comments in favor of tiny functions with long names, shunning function arguments in favor of mutating state, polymorphism obsession, etc. So much of the concrete advice the book gives is just plain bad.

The reason people get more pissed off at Clean Code than they would at any other book that gives bad advice is the preachy and authoritative tone it uses. It frames people who don't do "Clean Code" as unprofessional and lazy, and this framing is very convincing to some people, as evidenced by some of the replies in this thread.

Re: "Clean" Code, Horrible Performance (2023)

#64
post #43
post #28

Earlier quoted context omitted.

If your compilers is any good it will inline, and do a better job than you of figuring out what should be inlined. For that matter function calls are generally fast so long as the objects you copy as part of the function call are not slow to copy (which they can be). There are exceptions to the above, but in general small functions are not a problem. What is a problem is large functions. I have seen functions that we…

> I have seen functions that were over 60,000 lines long That can't possibly be from a serious person.

Sadly it is serious and in production code. (I left there 15 years ago, I suspect it isn't in production anymore)

Worse, it was a giant switch, and the target system didn't have enough memory for all the code so there were different builds and the user would select which to load.

There was code like

   case foo:
     doSomething();
   #ifdef build_two
     doSomethingElse();
     break;
   case bar:
     SomeThing();
   #endif
     MoreThings();
     break;
Try to follow that mess.

Re: "Clean" Code, Horrible Performance (2023)

#65
post #56

Performance vs. Maintainability is the infinite debate, and it’s a mind numbing one because in the vast majority of professional roles you will have the opportunity to prefer neither.

And following Clean Code gives you neither. The book is written by someone with a very limited experience and the advice is either basic and obvious or harmful. People should just stop reading that book.

Re: "Clean" Code, Horrible Performance (2023)

#66

Earlier quoted context omitted.

It's a problem chosen by the author of Clean Code. How is it a strawman? The author of the article is directly refuting the style of the problem/solution that the original author chose, and arguably demonstrated a better approach. That is not a strawman.

Using `switch` is not a better approach if the design allows for outsiders to add their own shapes at a later time. Using `switch` probably is a better approach if the range is shapes is fixed and new shapes can't be added, especially if the language's `switch` statement requires that all valid cases be included.

Sure, but I don't see what this has to do with what I said? I was arguing against the parents assertion that the author's example was a strawman.

For your point, what part of the design shows claims that shapes are to be added/removed by outsiders? You should design for what you know and can reasonably predict. Nothing in the article seems to claim that this problem is situated on outsiders adding their own shapes?

Let's ground the example. Suppose I was writing some 2D collision checking library where these operations we're useful. Now I did Triangles, Rectangles and Circles. If I predict that arbitrary shapes should be added, how should I go about it?

The vtable way could work, but as the author showed, you're likely going to get hit with a fairly significant performance impact. Now if you can reason about your use case and see that its not in a hot loop, then the vtable way should be good to go. But if it was called a lot, then you want that to be performant and find a different method.

Some thinking can lead you to the fact that you don't need a new class at all, you just need a general Polygon object, and use the switch method. Or going by the article, you can precompute the information you need that is constant, area, # of points and add those to a dynamically allocated array (or large enough statically allocated one), and have the best of both worlds.

My point is, you can't really say which one is better until you actually know what your use case and the constraints on your system/users. We need to know how the code is used. People complain about this being a simple example, but its an example that was in the "Clean Code" book. What's important is to realize that the Clean Code version might not be worse in terms of hard to measure things, like maintainability or eligibility, but it is empirically worse for performance, and that trade off matters for many use cases.

Re: "Clean" Code, Horrible Performance (2023)

#67
post #19

Yes, a toy problem only needs a simple implementation. This is a straw man. And I don't even like Robert Martin's Clean Code, but the author is not addressing where this style actually provides benefits. When you're updating 23 if-statements because you had to add support for some new business workflow, you'll wish you had a conceptual entity that encapsulated the operations on the type of workflows so you just had t…

> When you're updating 23 if-statements because you had to add support for some new business workflow, you'll wish you had a conceptual entity that encapsulated the operations on the type of workflows so you just had to implement them in one place.

Polymorphism won't get rid of the 23 if statements, it will just replace them with 23 method implementations. Then when you try to serialize that "conceptual entity" to a file or network socket you'll yearn for the if statements once more.

The main benefit of polymorphism is that it allows you to modify one part of a program without recompiling the other parts. In the absence of pre-compiled modules, polymorphism is isomorphic to branching/switch statements:

https://en.wikipedia.org/wiki/Expression_problem

Re: "Clean" Code, Horrible Performance (2023)

#68
I think performance generally trades along a different axis: open-world vs closed-world assumptions. There are many cases where closed-world assumptions may confer performance benefits, such as tree-shaking, whole program optimization, and using switch statements rather than a class hierarchy. Whereas designing for extensibility necessarily precludes some of those choices (though it doesn’t necessarily require OOP, for example registering a handler in a table). In other words, it’s easier to optimize a problem that is fixed and well-understood, versus one flexible and unknown. Take that ideas to the extreme and end up at ASIC bitcoin miners.

Re: "Clean" Code, Horrible Performance (2023)

#69

Earlier quoted context omitted.

Using `switch` is not a better approach if the design allows for outsiders to add their own shapes at a later time. Using `switch` probably is a better approach if the range is shapes is fixed and new shapes can't be added, especially if the language's `switch` statement requires that all valid cases be included.

Sure, but I don't see what this has to do with what I said? I was arguing against the parents assertion that the author's example was a strawman. For your point, what part of the design shows claims that shapes are to be added/removed by outsiders? You should design for what you know and can reasonably predict. Nothing in the article seems to claim that this problem is situated on outsiders adding their own shapes? L…

It's a strawman because Muratori took an obvious toy example meant to illustrate a concept (using classes and methods to dispatch on operations instead of using a series of if/else's as in Martin's prior example) and focused on what it did poorly (performance), but it was not meant as an example of high-performance code. It was an illustration of a concept that fit into a page. Attacking an illustrative example for not being realistic is kind of dumb.

I had to track down a copy of the book because I didn't have one on hand (thanks internet!) but that example is from chapter 6. The first listing is actually close to Muratori's code (except using classes instead of a tagged struct for dispatch but still using a procedural approach rather than dispatching off of methods), the second listing is the OO one that Muratori starts with. The point being illustrated is summed up in the book in these two quotes:

> Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.

> Procedural code makes it hard to add new data structures because all the functions must change. OO code makes it hard to add new functions because all the classes must change.

And amusingly, given that this whole thing is meant as a criticism of Martin and Clean Code he has this right after those two statements:

> Mature programmers know that the idea that everything is an object is a myth. Sometimes you really do want simple data structures with procedures operating on them.

So at least in the book, he has right here, after the "bad" code Muratori is criticizing, addressed the fact that you need to choose your representation based on your circumstances.

Re: "Clean" Code, Horrible Performance (2023)

#70
post #61

Earlier quoted context omitted.

My personal benchmark for 'maybe this function is too long' is when it doesn't fit on the page.

I don't think any such benchmark should exist. As long as the function only does one thing there is no upper limit. Artificially splitting a large function only reduces readsbility. What would you name the parts? do_stuff1(), do_stuff2(), do_stuff3()? I have seen very clean codebases with a handful very long functions, but they were no issue she nice they only did one thing. I personally write quite short functions b…

There aren't usually many domains where a process can't be described as a series of steps. Deciding what those are called, and structuring data in such a way that it each of those steps works sensibly can be challenging, but that is the process of making code comprehensible.

I can remember as a novice that I would write an entire program in a single, many-thousand line function, unable to see where the boundaries between functions should be. With experience and expertise in the domain, it becomes easier to see where those should be.

Post reply on HN