The human typewriter, or why optimizing for typing is short-sighted
The article highlights the drawbacks of optimizing code for typing speed, advocating for readability and clarity over efficiency, as obfuscated code increases mental strain and confusion among developers.
Read original articleThe article discusses the drawbacks of optimizing code for typing speed, particularly through the use of auto and template type deduction. The author, Felix Klinge, argues that such practices can obfuscate code, making it harder to read and navigate, which ultimately increases the mental strain on developers. He emphasizes that code should be optimized for readability and ease of debugging rather than for typing efficiency. Klinge provides a code example to illustrate his point, showing how the use of auto types can lead to confusion about variable types and their implications. He contrasts this with a rewritten version of the code that clarifies types and improves understanding. The author encourages developers to consider the perspective of others who may read their code, advocating for clarity and explicitness in programming practices.
- Optimizing for typing speed can lead to obfuscated code.
- Readability and ease of debugging should be prioritized in coding practices.
- The use of auto types can create confusion about variable types and their usage.
- Clear and explicit code improves understanding for all developers.
- Developers should consider the perspective of others when writing code.
Related
Optimizing JavaScript for Fun and for Profit
Optimizing JavaScript code for performance involves benchmarking, avoiding unnecessary work, string comparisons, and diverse object shapes. JavaScript engines optimize based on object shapes, impacting array/object methods and indirection. Creating objects with the same shape improves optimization, cautioning against slower functional programming methods. Costs of indirection like proxy objects and function calls affect performance. Code examples and benchmarks demonstrate optimization variances.
Why We Build Simple Software
Simplicity in software development, likened to a Toyota Corolla's reliability, is crucial. Emphasizing straightforward tools and reducing complexity enhances reliability. Prioritizing simplicity over unnecessary features offers better value and reliability.
Beyond Clean Code
The article explores software optimization and "clean code," emphasizing readability versus performance. It critiques the belief that clean code equals bad code, highlighting the balance needed in software development.
Clang vs. Clang
The blog post critiques compiler optimizations in Clang, arguing they often introduce bugs and security vulnerabilities, diminish performance gains, and create timing channels, urging a reevaluation of current practices.
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.
Type info is needed on function signatures mostly so people know how to call the thing. That's why Javascript and Python have acquired bolt-on typing systems. It's also why cross-function type inference hasn't caught on. It can be done technically, but it just confuses the humans.
Humans are not good at maintaining consistency between the thing right here and that other thing way over there. It's best not to design systems which require that.
This poor Neovim user also has LSP with inline hints, hover and help like IDEs.
Vim/Emacs aren't just the dumb text editors anymore.
The author certainly has that right, because the post steps on two programming religion landmines, from how I read it:
1. strict static typing (without type inference) is good. 2. code should be written to allow IDEs to enhance navigability, rather than written on the assumption that IDEs will be the sole provider for navigability.
I believe there is a point to be made in the "when we don't know what we're getting back, that harms navigability" camp. But as another commenter posted, there's a point to be made in the "when we overspecify what we're getting back every time, that can harm readability, too" camp.
I can't express where this balance is. It's somewhere between poetry and a legal document, the prose where you can really get into a good book and enjoy the world that the author presents. Some people really like the beauty of a short poem. Other people may require precise wording that leaves no room for enjoyment or interpretation. The rest of us can have the majority of fun somewhere in between.
Where that "in between" equivalent would be in my day-to-day programming, I'm not entirely sure, because what I'm writing could be a short script where brevity is vital (poetry-ish) vs some section of unfortunately highly complex code with lots of tests for edge cases (legalese), and all the other code where I'm still world-building and conveying ideas (prose). And I believe that complexity should be spelt out as precisely as it can in the code itself, rather than rely on the hope that somebody else is using the same IDEs and features as me. I've tried using type inference where it seems fine to use, and then spelling out the exact type that a variable wants where it isn't clear what might get returned, all in the same app, but it comes across as sloppily inconsistent in my mind. Ah well.
The code is listed as c++. However, it is using a style that will result in problems.
First thing that jumped out at me is using const char* for strings. Using this muddies ownership and doesn’t store the length of the buffer which can result in all sorts of fun. Add to that that many times paths are formed by string concatenation, and it is looking like a code smell.
Second, there is no RAII and just manual management of resources.
These problems are far more likely to cause issues that the use of type deduction which by now has pretty good tooling support and is used successfully in many languages. Of course, not using RAII, using raw pointers make it tricky, but you shouldn’t be using those like that anyway.
LLVM has a well thought out stance on auto too: https://llvm.org/docs/CodingStandards.html#id29
That being said, there is a third option here:
- type `auto`
- have an autoformatter that replaces `auto` with `std::vector<std::string>::iterator` or whatever the abomination of a type you need is :P
Untyped, non-descriptive objects calling each other randomly, with no chance for the reader to figure out what is going on.
So in this case auto is harmful. In many other cases it isn't.
I like to think of myself as a good programmer, but whenever I encounter code where I have to figure out what "x" means, when it could have been a speaking variable like "accumulative_duration_ms" I feel like someone is trying to be clever.
I see using auto in a similar light. Explicit return types are good. In fact there's a trend to retrofit typing into languages that don't have it. You showing me that you value not thinking about the return type over specifying explicit return types is a red flag to me.
If we as programmers should value anything, it is the time and mental resources of the person who has to read our code in the future — very often that person is going to be you, yourself.
Use auto when the local code shouldn't care about the type as a way of signifying that the local code shouldn't care about the type. It doesn't happen all the time, but it does happen sometimes.
Don't use auto when the code needs to care about the type.
This comment is sort of ironic given the title of the piece. As a Vim user, I opened it expecting to be called out for optimizing for typing.
Starts with an interesting claim "don't optimize for typing", but then it completely fails to prove it, and confuses itself in thinking that `auto` is an optimization for typing.
`auto` is:
- A way to express types that are impossible or truly difficult to express, such as iterators, lambdas, etc
- A way to optimize reading, by limiting the redundancy
- A way to optimize maintenance, by limiting the amount of change brought by a refactor
The insistence on notepad or "dumb editors" is also difficult to grasp. I expect people reviewing my code to be professionally equipped.
Lastly the example mostly fails to demonstrate the point.
- There's a point made on naming (distinct from `auto`): absent a wrapping type, `dataSizeInBytes` is better than `dataSize`. The best way though is to have `dataSize` be a `Bytes` type that supports conversion at its boundaries (can be initialized from bytes, MB, etc)
- What's the gain between:
auto dataSet = pDatabase->readData(queryResult.getValue());
and DatabaseDataSet dataSet = pDatabase->readData(queryResult.getValue());
The `dataset` part can be inferred from the naming of the variable, it is useless to repeat it. The `Dabatase` is also clear from the fact that we read data from a db. Also, knowing the variable has this specific type brings me absolutely nothing.- Their point about mutability of the db data confused me, as it is not clear to me if I can modify a "shadow copy" (I suppose not?). I suggest they use a programming language where mutating something you should not it a compile time error, it is much more failsafe than naming (which is hard)
I'm sad, because indeed one shouldn't blindly optimize for typing, and I frequently find myself wondering when people tell me C++ is faster to write than Rust, when I (and others) empirically measured that completing a task, which is the interesting measure IMO, is twice as fast in the latter than in the former.
So I would have loved a defence of why more typing does not equate higher productivity. But this ain't it.
Related
Optimizing JavaScript for Fun and for Profit
Optimizing JavaScript code for performance involves benchmarking, avoiding unnecessary work, string comparisons, and diverse object shapes. JavaScript engines optimize based on object shapes, impacting array/object methods and indirection. Creating objects with the same shape improves optimization, cautioning against slower functional programming methods. Costs of indirection like proxy objects and function calls affect performance. Code examples and benchmarks demonstrate optimization variances.
Why We Build Simple Software
Simplicity in software development, likened to a Toyota Corolla's reliability, is crucial. Emphasizing straightforward tools and reducing complexity enhances reliability. Prioritizing simplicity over unnecessary features offers better value and reliability.
Beyond Clean Code
The article explores software optimization and "clean code," emphasizing readability versus performance. It critiques the belief that clean code equals bad code, highlighting the balance needed in software development.
Clang vs. Clang
The blog post critiques compiler optimizations in Clang, arguing they often introduce bugs and security vulnerabilities, diminish performance gains, and create timing channels, urging a reevaluation of current practices.
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.