Comment by motorest
9 months ago
> It's striking to me how out of touch Martin seems to be with the realities of software engineering in this transcript. Stylistic refactors that induce performance regressions, extremely long and tortured method names for three-line methods, near-total animus towards comments ... regardless of who is right/wrong about what, those takes seem like sophomoric extremism at its worst, not reasoned pragmatism that can be applied to software development in the large.
I think you're talking out of ignorance. Let's take a moment to actually think about the arguments that Uncle Bob makes in his Clean Code book.
He argues in favor of optimizing your code for clarity and readability. The main goal of code is to help a programmer understand it and modify it easily and efficiently. What machines do with it is of lower priority. Why? Because a programmer's time is far more expensive than any infrastructure cost.
How do you make code clear and easy to read? Uncle Bob offers his advise. Have method names that tell you what they do, so that programmers can easily reason about the code without having to even check what the function does. Extract low-level code to higher level methods so that a function call describes what it does at the same level of detail. Comments is a self-admission you failed to write readable code, and you can fix your failure by refactoring code into self-descriptive member functions.
Overall, it's an optimization problem where the single objective is defined as readability. Consequently, it's obvious that performance regressions are acceptable.
Do you actually have any complain about it? If you read what you wrote, you'll notice you say nothing specific or concrete: you only throw blanket ad hominems that sound very spiteful, but are void of any substance.
What's the point of that?
> Maintainability/appropriate factoring are subjective qualities that depend a lot on the project, the other programmers on it, and the expectations around how software engineering is done in that environment.
The problem with your blend of arguments is that guy's like you are very keen on whining and criticizing others for the opinions they express, but when lightly pressed on the subject you show that you actually have nothing to offer in the way of alternative or guideline or anything at all. Your argument boils down to "you guys have a style which you follow consistently, but I think I have a style as well and somehow I believe my taste, which I can't even specify, should prevail". It's fine tha you have opinions, but why are you criticizing others for having them?
> Comments is a self-admission you failed to write readable code, and you can fix your failure by refactoring code into self-descriptive member functions
This may be true for some cases, but I don't see a non-contrived way for code to describe why it was written in the way it does or why the feature is implemented the way it is. If all comments are bad, then this kind of documentation needs to be written somewhere else, where it will be disconnected from the implementation and most probably forgotten
> This may be true for some cases, but I don't see a non-contrived way for code to describe why it was written in the way it does or why the feature is implemented the way it is.
I have to call bullshit on your argument. Either you aren't even looking because you have the misfortune of only looking at bad code written by incompetent developers, or you do not even know what it looks like to be able to tell.
The core principles are quite simple, and are pervasive. Take for example replacing comments with self-descriptive names. Isn't this something obvious? I mean, a member function called foobinator needs a combination of comments and drilling down to the definition to be able to get a clue on what it does. Do you need a comment to tell what a member function called postOrderMessageToEventBroker does?
Another very basic example: predicates. Is it hard to understand what a isMessageAnOrderRequest(message) does? What about a message.type == "command" && type.ToUpperCase() == "request" && message.class == RequestClass.Order ? Which one is cleaner and easier to read? You claim these examples are contrived, but in some domains they are more than idiomatic. Take user-defined type assertions. TypeScript even has specialized language constructs to implement them in the form of user-defined type guards. And yet you claim these examples are contrived?
I'm starting to believe all these vocal critics who criticize Uncle Bob or Eric Evans or any other author are actually talking out of sheer ignorance about things they know nothing about. They read some comment in some blog and suddenly they think they are an authority on a subject they know nothing about.
So much noise.
> Do you need a comment to tell what a member function called postOrderMessageToEventBroker does?
Which event broker? Will I get a response via some callback? What happens if the sending fails, is there a retry mechanism? If yes, how many retries? What happens when the retry count is exceeded? Will the order‘s ID be set by this method? Is the method thread-safe? Which errors can be thrown? „Don‘t call this before the event broker has warmed up / connected“. Etc etc
> Do you need a comment to tell what a member function called postOrderMessageToEventBroker does?
Obviously not and the comment you're replying to hasn't asserted otherwise. They say, clearly, that comments should explain the _why_, postOrderMessageToEventBroker explains only the _what_ (which is reflected in the verbiage of your question). Fortunately comments are practically free and we're not limited to doing the reader one-favor-per-statement, we can explain _both_ the why with a comment (when it's not obvious) and the what with clear function names.
> I'm starting to believe all these vocal critics who criticize Uncle Bob or Eric Evans or any other author are actually talking out of sheer ignorance about things they know nothing about.
I've been programming for 60 years in many different fields. I was programming long before he was. It is possible that I have written more code than he has in more languages (36 at last count), so my criticism of his are based on real-world experience.
What I was refering to was the "why", not the "what" or "how". This is not a good function name to my eye, but YMMV: get-station-id-working-around-vendor-limitation-that-forces-us-to-route-the-call-through-an-intermediary-entity.
Instead, a comment can clearly and succintly tell me why this implementation is seemingly more complex than it needs to be, link to relevant documentations or issues etc.
> The main goal of code is to help a programmer understand it and modify it easily and efficiently. What machines do with it is of lower priority.
This mentality sounds like a recipe for building leaky abstractions over the inherent traits of the von Neumann architecture, and, more recently, massive CPU parallelism. Bringing with it data races, deadlocks, and poor performance. A symptom of this mentality is also that modern software isn‘t really faster than it should be, considering the incredible performance gains in hardware.
> Comments is a self-admission you failed to write readable code
I‘m not buying this. It’s mostly just not possible to compress the behavior and contract of a function into its name. If it were, then the compiler would auto-generate code out of method names. You can use conventions and trigger words to codify behavior (eg bubbleSort, makeSHA256), but that only works for well-known concepts. At module boundaries, I‘m not interested in the module‘s inner workings, but in its contract. And any sufficiently complex module has a contract that is so complex that comments are absolutely required.
> This mentality sounds like a recipe for building leaky abstractions over the inherent traits of the von Neumann architecture, and, more recently, massive CPU parallelism. Bringing with it data races, deadlocks, and poor performance.
No,not really. Just because you think about how to name functions and what portions of your code should be easier to read if the were extracted to a function,that doesn't mean you are creating abstractions or creating problems.
The rest of your comments on von Neumann architecture etc is pure nonsense. Just because your code is easy to read it doesn't mean you're writing poetry that bears no resemblance with how the code is executed. Think about what you're saying: what is the point of making readable code? Is it to look nice at the expense of bugs, or to help the developer understand what the code does? If it's the latter, what point do you think you're making?
I was quoting you, where you said readability takes precedence over technical concerns. That‘s what I‘m challenging.
Every extra function call and object instantiation has a real cost, and abstracting ourselves away from the bare metal means we need to pay the price in terms of performance. Some very nicely readable algorithms are just sub-par in all dimensions except readability. We should optimize for performance and correctness, and readability comes second.
Code like Uncle Bob suggests is not easier to read and understand, it is harder, IMO and that of many others. Since the disagreement starts from this any further discussion is impossible.
[flagged]
I wrote IMO for a reason. The issue with your statement is that you are implying I disagree the improvements in clean code aren't improvements. They are for the most part, but they are improvements of those particular examples, and do not generalize. The function size thing in particular is absolutely stupid. There are also different improvements that could be done.
In the real world optimizing for the text of the program is the wrong thing to optimize for. It doesn't matter if the text reads nicely if the behavior is wrong. Then what you want is code optimized for debugging, and code optimized for debugging wants to avoid jumping around since the more information you see in a single stack frame the better.
Similar issues with just OOP style code in general. Isolated state is nice, distributed isolated state is a nightmare. Porting that challenge over from distributed computing makes debugging the program harder, not easier, since you must now understand the history of communication between the objects to understand how a certain global state was reached in aggregate.
Contrast that with a sequence of steps operating in that larger state directly, it's way easier to follow the logic since it is explicitly written down in a single place.
Comments are also much better than convoluted method names. Why comments I think even Bob would agree are important, but How comments are extremely useful. Consider python libraries that write out example code in the documentation string with the outputs (that gets turned into automatic tests no less). Does the method name matter that much then? Not really.
Consider also APL and its fans. While I'm not a fan the proponents make a good point why they like it: you can see much more of your program in one go and sequences of symbols form words with precise meaning.
Basically, mathematical notation and Kanji rolled into one. How does that fit into Bob's Clean Code approach?
Here is an example: https://qntm.org/clean
> Shit-talking while hand-waving adds nothing to the discussion.
This is not presuming good faith, as he guidelines ask that we do.
> Comments is a self-admission you failed to write readable code, and you can fix your failure by refactoring code into self-descriptive member functions
# This is not the way I wanted to do this, but due to bug #12345 in dependency [URL to github ticket] we're forced to work around that.
# TODO FIXME when above is done.
Oh no, I so failed at making self-descriptive code. I'm sorry, I totally should've named the method DoThisAndTHatButAlsoIncludeAnUglyHackBecauseSomeDubfuckUpstreamShippedWithABug.
> What machines do with it is of lower priority. Why? Because a programmer's time is far more expensive than any infrastructure cost.
This assumes that code runs on corporate infrastructure. What if it runs on an end user device? As a user I certainly care about my phone's battery life. And we aren't even talking about environmental concerns. Finally, there are quite a few applications where speed actually matters.
> Comments is a self-admission you failed to write readable code, and you can fix your failure by refactoring code into self-descriptive member functions.
Self-explaining code is a noble goal, but in practice you will always have at least some code that needs additional comments, except for the most trivial applications. The world is not binary.
I'm not going to spend a long time responding to your comment, since it seems accusatory and rude; if you modify it to be more substantive I'll happily engage more.
The one specific response I have is: it's not that I
> say nothing specific or concrete: [I] only throw blanket ad hominems that sound very spiteful
...rather, it's that I'm criticizing Martin's approach to teaching rather than his approach to programming. I expand on that criticism more in an adjacent comment, here: https://news.ycombinator.com/item?id=43171470