| > Yes, there are people who create a mess with abstraction. This happens in every language, in Java people create FactoryFactories, in Haskell people play type tetris, in Ruby, people abuse metaprogramming and in Go, I assume some people go overboard with code-gen. It's possible in any language and yet some languages' codebases are consistently worse than others ;) If you create a culture of cleverness, implicitness and metaprogramming, that's what the programmers using your language will do. It's self-selection to an extent. "I've suffered long from the Ruby ecosystem's mentality of 'look at what I can do!' of self-serving pointless DSL's and frameworks and solemnly swore to myself to stay away from cute languages that encourage bored devs to get 'creative'." [1] "I worked at a Scala shop about 10 years ago. Everyone had their own preferred "dialect", kind of like C++, resulting in too much whining and complaining during code reviews. IMHO, the language is too complex." [2] > And all the while, every one of these lines could be mutating some shared state That's where the obvious code helps. Let's circle back. > I still don't know what people mean by "obvious" code. The Zen of Python is a nice primer: [3]. A beautiful display of taste right there. A few concrete examples: - "Explicit is better than implicit." Explicitly returning errors means we get to see every single point at which something could error out - explicit, as opposed to exceptions that could implicitly propagate from any line of code, with no way to tell. Preferring pure functions - a pure function is a black box with a clearly drawn boundary line of input->output. Trivial to reason about in isolation. No automatic type conversions. No global state - any part of the code could change it. No metaprogramming - you've learned Ruby but now some parts of the language have been changed to mean something completely different! "The syntax has so many ways of doing things that it can be bewildering. As with Macro-based languages, you are always a little uncertain about what your code is really doing underneath." [4] - "There should be one-- and preferably only one --obvious way to do it." Uniform code. Iterating through an array always looks the same, so if the code you're looking at does it differently, you'll pay attention. [1] https://news.ycombinator.com/item?id=13482459 [2] https://news.ycombinator.com/item?id=31219392 [3] https://peps.python.org/pep-0020/ [4] https://alarmingdevelopment.org/?p=562 |
I don't oppose the "principles" you've quoted, but they would just as easily apply to e.g. Haskell (maybe except for the "there's only one way to do it" which however has never been true of any language, including Python).
I feel like you missed my larger point. It's not terribly difficult to write code that you can understand line by line. It's incredibly hard to write a huge code base in a way that you can reason about many code paths simultaneously, however. That's where the abstractions start to make sense.
I don't understand why people think that those facilities were created just to piss people off? People were facing real problems. Yes, sometimes the cure is worse than the disease. Use abstractions judiciously and by employing common sense. That doesn't mean you should never use them.
I've seen over- and underabstracted code (as well as just plain wrongly abstracted code). Both of these situations really suck.
Honestly, what annoys me a bit here is your smugness. It seems as if you feel you've figured out how to write good code, and all the other idiots who use Ruby, Java, etc. haven't. But I don't believe you. Nobody in this industry knows how to write "good" code. I don't even think we know what "good" code is. The most we can do is try our best, learn about better ways to do things, discuss approaches and use our judgment.