[HN Gopher] My story on "worse is better" (2018)
       ___________________________________________________________________
        
       My story on "worse is better" (2018)
        
       Author : rui314
       Score  : 165 points
       Date   : 2022-05-11 13:43 UTC (9 hours ago)
        
 (HTM) web link (www.sigbus.info)
 (TXT) w3m dump (www.sigbus.info)
        
       | CipherThrowaway wrote:
       | IMO it's not that the simplest solutions are the best but that
       | the "better" complex solutions are not actually available
       | upfront. They can only be made with hard-won domain knowledge.
       | The design policy for lld v1 per this article encoded many
       | assumptions that turned out to be untrue in practice (like the
       | importance of platform independence). If they had been true then
       | the extra complexity might have been worth it. Over time the
       | simpler lld v2 might accrue its own complexity that better
       | reflects learned experience.
       | 
       | Code is a tool for exploring and understanding problems as much
       | as it is about solving them. Sophisticated solutions can't be
       | designed before they are validated.
        
         | hcarvalhoalves wrote:
         | "Programming as Theory Building by Peter Naur"
         | 
         | https://pages.cs.wisc.edu/~remzi/Naur.pdf
        
         | duxup wrote:
         | My thing is I go simple. I'm good, maybe messy. Finally see
         | enough / think I know a good abstraction and pull the trigger
         | and later I find out ... oh man I was wrong. Knowing when you
         | know is the hard part.
         | 
         | I've got some abstractions out there I wrote early on when I
         | didn't think I coded well and they have lived for years and
         | saved tons of time.
         | 
         | Others don't live long :(
        
           | lamontcg wrote:
           | https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction
           | 
           | So many times I've taken code that was a mess because someone
           | tried blindly DRY code for the sake of being DRY and rub
           | abstractions on top of it and I've reverted the code back to
           | being simple copypasta and its become so much more clearer
           | and robust. Then you can look at the result and a simple
           | abstraction may pop out which can reduce enough code
           | duplication that the result is satisfactory (it may require a
           | bit more boilerplate in the subclasses or whatever, but
           | nothing likely to be brittle under future fixes).
        
             | bcrosby95 wrote:
             | The nice thing about dealing with an overly-DRY codebase is
             | you can unwind the abstractions.
             | 
             | But an underly-DRY codebase... good luck. Copypasta tends
             | to accumulate minor differences and figuring out if those
             | minor differences matters can become very time consuming.
        
               | d0mine wrote:
               | Not-quite right abstraction also can accumulate minor
               | differences where it is forced on use-cases that fit
               | poorly.
               | 
               | It is better to under-abstract and keep some duplication
               | than over-complicate and miss. Complexity snicks up on
               | you (it is a time bomb).
        
               | corrral wrote:
               | > Copypasta tends to accumulate minor differences and
               | figuring out if those minor differences matters can
               | become very time consuming.
               | 
               | The DRY version of this is functions/constructors/methods
               | that take a stupid number of parameters, many with
               | unclear purposes.
        
               | Jtsummers wrote:
               | If it's unclear, then it's poor code or poor
               | documentation or both. Sane developers will provide a way
               | to obtain default or common configurations rather than
               | forcing you to figure out the 100 different tunable
               | options.
        
               | skrtskrt wrote:
               | All the libraries I love and use the most have tons of
               | parameters _but they are really well documented_
               | including their parameters ' interactions with each
               | other.
        
               | corrral wrote:
               | I don't mean well-considered and documented libraries, I
               | mean the thing where someone goes to DRY up a codebase
               | and keeps thinking "oh, if I just add a parameter this
               | function can also handle _this_ one-off case over here...
               | " over, and over, and over, until you've got this
               | function with a name that makes it _look_ straightforward
               | but for some reason it wants three strings, two of which
               | should actually be nulled in most cases (and god help you
               | if you fill in a value when you don 't need them), an
               | integer for unclear reasons but it's the same value in
               | _every_ call you can find, and half a dozen booleans that
               | you 'll have to go read the source to figure out, because
               | some of them do more than the variable name in the
               | signature implies.
               | 
               | Good intentions at every step, but a Frankenstein's
               | monster of a function (or entire class, sometimes) in the
               | end
               | 
               | It's the DRY equivalent of having 20 slightly-different
               | copypastes all over a codebase.
        
               | whatshisface wrote:
               | > _Copypasta tends to accumulate minor differences and
               | figuring out if those minor differences matters can
               | become very time consuming._
               | 
               | Welcome to the field of genetics.
        
         | kazinator wrote:
         | The software engineering field is terrible at handing down
         | domain knowledge.
         | 
         | Part of the problem is that it's next to impossible to separate
         | the facts from the religion in software domain knowledge.
         | Software artifacts are simultaneously art, technology. math and
         | religion.
         | 
         | It's also hard to separate the abstract knowledge that is
         | broadly applicable from its original context where it was hard
         | won: the particular operating systems, toolchains and tech
         | stacks.
         | 
         | Even that knowledge which is separable is mired in the jargon
         | of those systems, so that it looks like it is specific to them.
         | If those systems are long obsolete, then it's easy to dismiss
         | anything that is robed in their jargon as being obsolescent by
         | association.
         | 
         | If civil or electronic engineering were like software, then
         | every five years, someone would be reinventing a class B push-
         | pull emitter follower amplifier output stage, or Pratt truss,
         | under different names.
        
       | eikenberry wrote:
       | > "It says that lazily-looking code that does not provide a
       | consistent interface is sometimes actually better than neatly
       | layered, consistent one."
       | 
       | I find this an odd take on that paper. To me it has always been
       | about how simplicity is more important than correctness. And
       | while the authors take doesn't conflict with WiB, I do think they
       | miss the point.
       | 
       | > "Simplicity of implementation is very, very important, and you
       | can sometimes sacrifice consistency and completeness for it."
       | 
       | They almost get it in the conclusion. They are starting to see
       | the important of simplicity, but still are fixed on correctness.
       | Simplicity is not something you sacrifice correctness and
       | completeness for "sometimes", it always wins if there is a
       | contest. It is always more important (at least in line with WiB).
        
       | golergka wrote:
       | > Here is the rule: if a user can trigger an error condition by
       | using the linker in a wrong way, the linker should print out a
       | proper error message. However, if the binary of an input file is
       | corrupted, it is OK for the linker to simply crash.
       | 
       | One of the most useful ideas in developing reasonably complex
       | systems that I encountered is treating different types of errors
       | differently. There's a place for both panics/exceptions on one
       | hand result monads/error messages on another.
        
       | hprotagonist wrote:
       | There's some commonality here between this sort of "worse is
       | better" and the observation that a meticulously neat and tidy,
       | fastidiously clean {desk, notetaking system, editor
       | configuration, ...} is a good indicator that its owner doesn't do
       | anything worthwhile with it.
       | 
       | The real world is messy. Things that come into contact with the
       | real world will acquire a little bit of wear and mess. If it's
       | all still brilliantly clean and tidy, you can't have done
       | anything useful yet!
        
       | avgcorrection wrote:
       | This ain't "worse is better". If the end-user has no worse of a
       | user experience with the supposedly worse-is-better interface or
       | program--most notably in this case if the linker never in
       | practice gives a bad user experience on bad input (perhaps
       | because it never happens)--then it's not really "worse".
       | 
       | The central tenet of worse-is-better is to prioritize
       | implementation simplicity over user experience. But if you
       | simplify the implementation since some features _are never used_
       | and not needed then you haven't even had to make a choice on that
       | spectrum--you have just cut out unneeded cruft.
       | 
       | In fact the user experience has improved since it is faster...
        
         | ncmncm wrote:
         | In fact the V1 implementation was not simpler. So, it was just
         | worse on every axis except its adherence to what people
         | apparently are taught in CS programs.
        
       | phendrenad2 wrote:
       | Not a good example of "Worse is Better". This is "Worse is
       | faster" which is much less interesting. The power of WIB is that
       | is applies even if the programs are equally fast.
        
         | renox wrote:
         | No, he also wrote that the V2 was easier to maintain..
        
           | phendrenad2 wrote:
           | Still misses the point of the original worse is better paper.
        
       | CTmystery wrote:
       | I have seen "worse is better" trotted out many many times, used
       | mostly as an appeal to authority instead of a clear instantiation
       | of the argument presented in the essay. I think this is because
       | the argument in the original essay is not crisply presented (at
       | least not to me). So authors take "worse" and "better" on some
       | random dimension that's beneficial to them in the moment, and
       | then appeal to the authority of this well respected essay to
       | "prove" that their approach is better.
       | 
       | This post is stating that they tried to generalize too much
       | instead of building to narrow use cases first. There is no need
       | to bring "worse is better" into it at all, IMO
        
       | chrchang523 wrote:
       | (2018)
        
         | CalChris wrote:
         | _The English translation of this essay was published in 2021._
        
       | sam_lowry_ wrote:
       | This echoes the "premature optimization is the root of all evil"
       | saying.
        
       | recursivedoubts wrote:
       | The worse is better essay is a great read:
       | 
       | https://www.dreamsongs.com/WorseIsBetter.html
       | 
       | Over time, I have come to believe that the problem is overly-
       | aggressive abstraction. It is very tempting for most developers,
       | especially good developers, to reach for abstraction as soon as
       | things get complicated. And this can pay off very, very well in
       | some cases. However, too much abstraction in a system leads to a
       | very, well, abstract code base that becomes hard to get a handle
       | on: there's no there there. You see this in the java world with
       | AbstractFactoryBuilderLookupServiceBuilders and so forth, and
       | with very elaborate type setups in functional programming
       | languages.
       | 
       | Concretizing the crucial bits of your system, even if that means
       | a few large, complex and gronky methods or classes, ends up often
       | making things more understandable and maintainable and,
       | certainly, debuggable.
       | 
       | John Ousterhout wrote a book that makes this point as well,
       | advocating for "deep" rather than "shallow" classes and methods:
       | 
       | https://www.goodreads.com/en/book/show/39996759-a-philosophy...
        
         | rob74 wrote:
         | The kind of codebase you describe with "elaborate type setups"
         | (multiple levels of inheritance, design patterns like Facade
         | used for "decoupling" etc.) make it very hard to read the code
         | and understand what it's doing (unless it's very well
         | documented), and because of that also make it harder to extend
         | without resorting to kludges. Or, if you want to extend it in a
         | way the original designer didn't foresee, you now have to
         | change 5 different classes to be able to access some private
         | property in some class.
        
         | funcDropShadow wrote:
         | > Over time, I have come to believe that the problem is overly-
         | aggressive abstraction.
         | 
         | Sometimes, yes, overly-aggressive abstractions are a problem.
         | But the author describes policies of v1 and v2 of the linker.
         | And I would say the most critical difference between them is,
         | that the authors of v2 had a better understanding of the
         | requirements that actually mattered. Therefore they were in a
         | better situation to evaluate the architecture and they were
         | able to make better trade-offs.
         | 
         | Deciding to trust object files as inputs might raise a red flag
         | for some people. In principle it could allow attacks/exploits
         | of the linker. But in reality for most threat models this does
         | not matter. Because the compiler generating object files has
         | the same level of trust as the linker. Companies that want to
         | provide an elf linker as a service product are out of scope.
         | Deciding what is in scope and what is out of scope is probably
         | one of the hardest decisions in product engineering. Because
         | many of us software engineers lean towards perfectionism or,
         | especially inexperienced developers are searching for the
         | silver bullet, that set of rules that enables them to develop
         | every product successfully.
         | 
         | [edited typos]
        
         | tynpeddler wrote:
         | One of the best programming aphorisms I've heard is "Everything
         | in programming can be solved with another layer of abstraction
         | except for the problem of to many layers of abstraction."
        
         | Bjartr wrote:
         | It can be worth understanding why the Java ecosystem evolved
         | that way. It's not because simplicity wasn't valued, but rather
         | it's not _code_ simplicity that 's valued. Rather, much of the
         | Java ecosystem is designed to allow dozens of independent
         | teams, totaling hundreds of developers, within a company (or
         | across companies) to build their small piece of the
         | application, with whatever build process is used by them. Then
         | you put all the .jar files in one bundle, and the
         | AbstractFactoryBuilderLookupServiceBuilders puts the pieces
         | together at runtime.
         | 
         | It's complex as hell code-wise, _but_ it simplifies the amount
         | of cross-team /cross-company alignment and synchronization that
         | has to happen in order to cut a new version of the application
         | containing hotfix 8495 for the part of the app maintained by
         | Steve's team.
         | 
         | There's actually a decent parallel between that and
         | Microservices. Microservices make maintenance of the whole more
         | complicated by introducing the network between pieces, but
         | allow each piece more flexibility in how it's developed.
        
         | ncmncm wrote:
         | I suspect the "Worse is Better" essay has caused untold harm.
         | It is written from the standpoint of a purist offended that the
         | world doesn't appreciate purity, complaining that the things
         | people end up using are built by pragmatic people. The lesson
         | seems to be that doing things better is punished. But that is
         | the wrong lesson.
         | 
         | The correct lesson is that the real world is not obliged to
         | conform to your personal model of "better". You have a personal
         | obligation to continuously adapt your model to match the real
         | world. This is the model of science, and is opposed to
         | Platonism. After you have adjusted your model, it is certain to
         | still not be right, and need further adjustment.
         | 
         | Usually "the world" you are obliged to adjust to has its own
         | problems. There are powerful forces making us favor
         | accommodating a Microsoft execution environment, even though
         | that execution environment has always been a cesspit. It
         | represents its own poor abstraction. Posix file system
         | semantics are another example. Von Neumann architecture and the
         | C abstract machine are not the only, or best way to organize
         | computational resources. It is important to recognize when
         | somebody else's pragmatic failure threatens to taint your own
         | models.
         | 
         | Lisp, RG's hobbyhorse, didn't get sidelined because of
         | Philistines. Lisp turned out not to be better, despite how
         | strongly RG felt about it. Instead of figuring out what about
         | Lisp was not right, he called things that were, along axes that
         | matter, more right "worse", preserving his personal model and
         | lessening readers' ability to reason about merit.
        
           | recursivedoubts wrote:
           | I don't agree at all. I think he was able to give a clear and
           | accurate analysis of why lisp failed, despite liking the
           | language so much. He also wrote critical responses to his own
           | essay under a pseudonym, with a back and forth that is quite
           | funny and demonstrates the ability to understand both sides
           | of the argument. In "Worse is better" he explicitly mentions
           | how that approach favors real-world application, because it
           | is so simple it is fast and is "good enough" and then can be
           | moved to 90% of the right thing.
           | 
           | All of this is to say: I don't agree with you, but I also
           | agree with you and I suspect he would as well, with
           | qualifications. And he would probably also disagree with you.
        
             | fileeditview wrote:
             | Perfect user name! Also this was my comment of the day..
             | nay week at least!
        
             | ncmncm wrote:
             | Not buying it. He still says "worse" and still writes
             | "90%". What he means is "not conforming to my personal
             | value system". He is dodging the crucial step of
             | discovering how his personal value system got so off-kilter
             | as to lead him to wrong choices, and fixing it.
        
           | r-bryan wrote:
           | There is an unfortunate fallacy here. Your notion "the real
           | world" conflates the physical world with a social milieu. The
           | physical world is (at this scale) immutable, so of course we
           | must conform to it and update our science-like models.
           | 
           | But there is no absolute requirement to conform oneself to a
           | social milieu. A social milieu changes. It can be altered. It
           | supports a vast number of models. And milieus overlap so
           | densely that one can just go play somewhere else.
           | 
           | Disclosure: I used to be a Lisp bigot, but I got better.
        
             | ncmncm wrote:
             | Agreed it is complicated. We have the principles of physics
             | and computational irreducibility, then physical realization
             | of state-machine designs to exploit those principles, then
             | social conventions around what is valued, languages
             | influenced by conventions, operating environments for
             | programs in them, and finally actual code in those
             | languages.
             | 
             | What makes a "better" Lisp program differs from what makes
             | a "better" C++ or Rust program. Besides fitness for
             | purpose, there is maintainability, energy cost to execute,
             | and results per unit time. What did you learn coding it?
             | Can it be the basis for something more ambitious? Is it
             | secure, deadlock-proof? Are its results accurate,
             | aesthetically pleasing, generative of insight?
             | 
             | We can get mired in detail, obscuring important truths. We
             | talk about performance a lot, not because we are obsessive,
             | but because it is a measure that is hard to fake. A faster
             | program says something fundamental about how your
             | computational resources are being directed to the target
             | results.
             | 
             | We can be misled by details of realizations of computation.
             | What is fast on a PDP-11 is not necessarily fast on a Ryzen
             | 5. But submitting to the rigors of performance for the best
             | machines we have is a discipline that connects us,
             | howsoever imperfectly, to the physical principles of
             | computation. It destroys illusion: if a variation seems
             | like it ought to be faster, but is actually slower, there
             | is no sugar-coating the fact. Hewing to physical
             | performance enforces a kind of honesty we don't get any
             | other way.
        
           | kragen wrote:
           | This will sound crazy from our perspective this year, but
           | from the perspective of the essay 31 years ago, Lisp
           | dominates software development today, just without the
           | parentheses. The top ten languages in
           | https://www.tiobe.com/tiobe-index/ are Python, C, Java, C++,
           | C#, Visual Basic, JS, assembly, SQL, and PHP. Of these, the
           | dialects of Lisp include Python, Java, C#, VB, JS, and PHP.
           | 
           | Remember that in 01991 all "serious" modern software was
           | either C, C++, Pascal, or assembly. BASIC, whose only data
           | structures were the string and the array, was for amateurs or
           | the MIS department, which mostly used COBOL, assembly, and
           | JCL. Fortran was established but was considered antiquated
           | (except by supercomputer people) and didn't have pointers.
           | 
           | If we compare these languages on the points pg lists in
           | http://www.paulgraham.com/diff.html, the earliest versions of
           | Lisp score 9/9, Python is 7/9, Java is 7/9, C# and VB are
           | Java with different syntax, and PHP is 5/9. By contrast, C is
           | 2/9, C++ is 3/9, Pascal is 3/9, assembly is 0/9, COBOL is
           | 0/9, Fortran 77 is 1/9. You can quibble a bit about these
           | numbers (do Pascal procedure parameters qualify as "a
           | function type" even though you can't store them in
           | variables?) but the broad division is very clear.
           | 
           | I think it was in the conversation where he originally wrote
           | that essay that Guy Steele said of his work on Java that they
           | had managed to drag all the C++ programmers kicking and
           | screaming about halfway to Common Lisp, so we should be
           | happy.
           | 
           | In terms of _syntax_ , Python or Java have nothing in common
           | with Lisp. But in terms of the issues you raise --
           | accommodating a Microsoft execution environment, POSIX
           | filesystem semantics, the Von Neumann architecture, the C
           | abstract machine, or just the tools they give you to analyze
           | problems -- they're just dialects of Lisp with slightly
           | different syntax (and more hair on eval, and sort of broken
           | symbols or no symbols).
           | 
           | In terms of "worse is better" of course Python and C# lean
           | just as hard on "worse" as C does.
           | 
           | I also think r-bryan's point in
           | https://news.ycombinator.com/item?id=31346478 is true,
           | beautiful, deep, and merits quoting:
           | 
           | > _Your notion "the real world" conflates the physical world
           | with a social milieu. The physical world is (at this scale)
           | immutable, so of course we must conform to it..._
           | 
           | > _But there is no absolute requirement to conform oneself to
           | a social milieu. A social milieu changes. It can be altered.
           | It supports a vast number of models. And milieus overlap so
           | densely that one can just go play somewhere else._
           | 
           | In that vein, it's worth noting that Linux got pretty far
           | before it ever had to accommodate a Microsoft execution
           | environment, though I did have coworkers in 01997 who thought
           | I was hopelessly unhip for preferring Unix (which they
           | thought of as antiquated) to Microsoft Windows.
        
           | marcosdumay wrote:
           | The essay is funny.
           | 
           | Lisp machines were clearly abandoned because of their price.
           | Every time I find some history about someone that actually
           | made that decision, the reasoning was exactly alike, those
           | machines costed more to keep than the Unix ones to install,
           | and were less capable due to outdated hardware.
           | 
           | Yet the essay goes all over the place, citing time to market
           | (that was completely irrelevant, UNIX was the newcomer, Lisp
           | machines were there already), university-based prejudice (yet
           | every single one decided the same at around the same time),
           | and blaming the user. The essay doesn't even talk about
           | money.
        
             | kragen wrote:
             | It would probably help you to understand the essay if you
             | knew that it was written by Richard P. Gabriel, the head of
             | the leading competitor to Lisp machines. His company's
             | product was a Lisp system that ran on Unix machines. What
             | he's personally best known for (aside from this essay) is
             | showing that smarter Lisp compilers on commodity hardware
             | like a 68020 could deliver performance that first equaled,
             | then exceeded the performance available from custom
             | silicon; the book he published on this subject was so
             | rigorous that many of the tests in it are still used today
             | for judging the performance of implementations of high-
             | level languages such as LuaJIT and V8.
             | 
             | You seem to think he was advocating Lisp machines, scoffing
             | at his essay based on that misconception. But if there was
             | a single person in history who worked hardest to destroy
             | Lisp machines, it was probably RPG.
        
         | polotics wrote:
         | Also, I often see developers running to the abstractions they
         | know (cough design patterns...) mostly because they're very
         | afraid of acknowledging they haven't grasped the real
         | complexity of a domain. By the time a pragmatic efficient
         | design emerges, you're on the second or third rewrite...
        
       | ncmncm wrote:
       | Cf: "Architecture Astronaut".
       | 
       | Abstraction always costs. This implies any abstraction you put in
       | that doesn't deliver commensurate benefits makes your code
       | fundamentally worse.
       | 
       | If you have an abstraction with a name that seems to say it does
       | X, but to be sure I have to trace through four other source files
       | plus an unknown number of dead ends just to see if it really does
       | exactly just X, and in the end it could have just been coded in
       | place, it has already cost way more than any benefit it could
       | yield.
       | 
       | Abstraction is an engineering tool, not a moral imperative. You
       | can always add abstraction later.
       | 
       | So, "Worse is Better" is at best misleading. _Better is better_.
       | But the measure of  "better" you have been using is likely to be
       | way off. People who think of themselves as smart tend to
       | undervalue simplicity. It is a personal failing.
        
         | KerrAvon wrote:
         | The flip side is that without abstraction your code becomes an
         | unmaintainable, fragile disaster, leading to bad outcomes for
         | the user. It's not as simple in a complex system as you make it
         | out to be.
        
           | ratww wrote:
           | With way too much abstraction your code also "becomes an
           | unmaintainable, fragile disaster, leading to bad outcomes for
           | the user". Both extremes are terrible. And GP is not
           | advocating using no abstractions.
        
           | ncmncm wrote:
           | Abstraction needs to be made to earn its keep. The massively
           | abstracted linker in TFA was, exactly, an unmaintainable,
           | fragile disaster. It was so bad they had to rewrite it from
           | scratch. The new one certainly has abstractions of its own.
           | Less harmful ones.
        
         | agentultra wrote:
         | It sounds like what you're talking about is _indirection_ , not
         | _abstraction_.
         | 
         | If you have to verify that "it does X" by following source
         | files and tracing execution then you're talking about
         | _indirection_.
         | 
         | An _abstraction_ has mathematically sound laws that can be
         | proven and introduce precise, new semantic layers to a program.
         | By definition one doesn 't have to think about the layers
         | underneath the abstraction and can instead think entirely in
         | the abstraction.
         | 
         | The difficulty with abstractions is that few practising
         | programmers know how to think even informally about
         | abstractions. The mistake of substituting abstraction for
         | indirection leads to the misguided notion that virtual methods
         | and classes are "abstractions." However if you try to formalize
         | these abstractions with relations and properties I think you
         | will find most of these proofs difficult, if not downright
         | impossible write. That's a good sign you don't have an
         | abstraction.
        
           | ncmncm wrote:
           | Indirection is how programming languages implement
           | abstraction. So, a distinction without a difference.
        
             | not2b wrote:
             | Not always. In C++ and Rust, in many cases the abstraction
             | penalty is completely eliminated by inlining or by making
             | an efficient concrete specialization. If this can be
             | achieved the abstraction penalty is paid only in compile
             | time.
        
               | ncmncm wrote:
               | That is just the compiler optimizing out the runtime
               | indirection. The effect on you as a programmer is
               | unchanged: you have to look through the same number of
               | source files either way.
        
             | agentultra wrote:
             | Right. All that work on type systems is purely indirection.
             | I want to run my code and the compiler keeps telling me I
             | can't access this place in memory because some other part
             | of my code is borrowing it. Or, what do you mean the
             | commutative property of this type class doesn't hold for my
             | type? Purely directing me away from programming, for sure.
        
       | hardwaregeek wrote:
       | What a lot of people seem to not understand is that mistakes or
       | failings are sometimes on purpose. If software is slow, sometimes
       | (not always!) it's because the software that focused on
       | performance didn't get traction with users and failed. Too many
       | programmers just see the immediate failings and not the larger,
       | successfully avoided failings that the software prevented due to
       | a tradeoff.
       | 
       | Likewise many programmers don't seem to get that the incentives
       | of a programmer are quite different than the incentives of a
       | manager. Programmers think "aw man my stupid manager is making me
       | push out features instead of refactoring, if I were in charge I'd
       | focus on code quality and performance", not understanding that
       | maybe, just maybe their manager might have different incentives
       | and a different perspective.
       | 
       | Worse is better is essentially a shorthand for understanding
       | product management and scoping.
        
       | 0xdeadbeefbabe wrote:
       | > It is OK to not aim to minimize the amount of code; reducing
       | the complexity is much more important.
       | 
       | Also, it's not OK to aim to increase the amount of code. //TODO
       | include both statements in the creed.
        
       | nyanpasu64 wrote:
       | > Since the linker's input file is created not by humans but by
       | the compiler, it is unlikely that the linker takes a corrupted
       | file as an input. Therefore, the policy did not actually increase
       | a crash rate. The code that trusts input was much simpler than
       | the one that does not trust any byte of an input file.
       | 
       | Interestingly I _have_ encountered crashes in Ninja (not lld),
       | caused by corrupted on-disk state I had to delete:
       | https://github.com/ninja-build/ninja/issues/1978. I think I
       | traced it down to a memory indexing or null pointer error, which
       | would've been caught by asserts but they were disabled in release
       | builds.
        
       | jt2190 wrote:
       | I've been thinking a lot about this kind of problem lately. My
       | thinking was triggered by a description of real-world contracts
       | by Lawrence Lessig, in a talk about crypto. [1] His point was
       | that in most real world contracts there are many, many undefined
       | contingencies for rare occurrences; the time and effort to nail-
       | down what each party should do in those cases is just not worth
       | it, and if any of them do actually occur everyone will go to
       | court for adjudication.
       | 
       | The software industry might be better off if we start making
       | explicit that we have a real trade off of time and effort between
       | designing a system that can handle all contingencies, and one
       | that needs adjudication occasionally, i.e. throws an error or
       | crashes, needs patching, etc. [2]
       | 
       | Notice that Rui's solution here was to basically allow lld to
       | just crash under rare, extraordinary cases. This seems reasonable
       | when written here, but in the real world suggesting that a system
       | be allowed to crash, ever, often gets very hard pushback.
       | 
       | [1] "Smart Contracts and DApps: Clarity versus Obscurity"
       | https://youtu.be/JPkgJwJHYSc?t=3512
       | 
       | [2] "Hard-assed bug fixin'" Joel on Software (2001)
        
         | ncmncm wrote:
         | This is where the programming-language exception feature is
         | valuable.
         | 
         | You could crash, but you can also throw. Somebody somewhere
         | sometime might be able to do a better job with the situation
         | than you can right there and then. Checking status codes all up
         | and down the call graph does not increase the likelihood that
         | something could be done, but costs in the meantime. Hiding the
         | checking behind abstractions does not reduce those costs.
        
           | jt2190 wrote:
           | > You could crash, but you can also throw. Somebody somewhere
           | sometime might be able to do a better job with the situation
           | than you can right there and then.
           | 
           | This is a very big assumption.
           | 
           | Edit: The assumption is that this day can ever come. The
           | author decided that in his system that day would likely never
           | arrive.
        
             | ncmncm wrote:
             | There's no assumption, at all. Either it happens or it
             | doesn't. If it doesn't, throwing an exception is a
             | controlled sort of crash.
             | 
             | There's no need for that person to decide, then and there,
             | when they can just as well leave the choice to somebody
             | else, at exactly zero cost.
        
               | jt2190 wrote:
               | > when they can just as well leave the choice to somebody
               | else, at exactly zero cost.
               | 
               | This is where the confusion lies. "Zero cost" here means
               | "it's a few lines of code, a few cpu cycles to handle it.
               | What's the big deal?"
               | 
               | But I'm not talking about a few lines of code or cpu
               | cycles, I'm talking about developer time. Leaving the
               | decision to someone else may take little no time to you,
               | today, but might incur a steep cost on someone else's
               | time tomorrow. Even worse is when you, with deep domain
               | knowledge, tempt a far less knowledgeable dev into
               | "handling" an error at a time and in a place that will be
               | difficult or impossible to handle, wasting their time.
        
               | ncmncm wrote:
               | You are _still_ not getting this. It costs _exactly zero_
               | more developer time to type  "throw x" than to type
               | "abort()". It places _exactly zero_ demand on anybody
               | else.
               | 
               | If somebody decides they want to catch the exception and
               | try something else, that is totally their choice, and
               | they can devote as much or as little time to getting
               | their idea working as they like. If they get it working,
               | good. If they give up first, that is fine too.
        
               | mst wrote:
               | Common Lisp's condition system arguably proves your
               | point.
        
       | draw_down wrote:
        
       | scoutt wrote:
       | I wouldn't called it "worse is better". Why not "less is better"
       | or "simpler is better"?
       | 
       | My take is that one should program in function of what the code
       | should do, and not in function of what it's comfortable to me (as
       | a developer).
       | 
       | Yes, it's a great feeling when your code fits like a jigsaw
       | puzzle, but also more complexity = more code being executed.
       | Behind that RAII, behind that _" operator="_ and that _" p = new
       | Struct"_, etc. there might be extra complexity for the sake of
       | developer's readability and comfortability. There is little or no
       | added value for the end user or the purpose of the program
       | itself.
       | 
       | Also the code should be written "for the now", not for "that
       | future feature it would be awesome to have someday like making it
       | compatible with every other library X, etc.".
       | 
       | At the end of the day, even without realizing it, your program is
       | slow.
       | 
       | I remember a developer where I work did a C# implementation of an
       | AT command parser, in which every AT command was a separate DLL.
       | It was very complex, and super slow. But the developer argued "if
       | I need a new AT command, I'll just add a new DLL". It might have
       | been _better_ for him as a developer, but it was _worse_ for the
       | end user and the system in general. The code died the day that
       | guy left the job.
        
         | razorfen wrote:
         | > Also the code should be written "for the now", not for "that
         | future feature it would be awesome to have someday like making
         | it compatible with every other library X, etc.".
         | 
         | The folksy software adage for this is YAGNI. (You Ain't Gonna
         | Need It)
        
         | klik99 wrote:
         | > I wouldn't called it "worse is better". Why not "less is
         | better" or "simpler is better"?
         | 
         | The original article called 'worse is better' was pretty
         | successful and widely read, and part of it was the title
         | grabbed people's attention. You could argue it's a rephrasing
         | of "less is more" or "do one thing well" concepts for the click
         | bait zeitgeist. That's not a bad thing - an old concept wrapped
         | up in a new way of expressing can keep the idea alive - anyway
         | it's funny and a little confusing, which might trigger someone
         | to engage with it differently. There's many concepts that I've
         | heard n times expressed in different ways only to have it click
         | on the n + 1 way of phrasing it.
        
           | pm215 wrote:
           | Also, the "PC-losering problem" presented as one of the
           | central examples in the original 'Worse is Better' really is
           | an example of 'worse' -- the unix approach gives a modest
           | reduction in kernel implementation complexity at the cost of
           | every single userspace program either taking a complexity hit
           | (retrying on EINTR) or being buggy in corner cases. This
           | isn't just "less" or "simpler" -- it's actively accepting
           | "worse" in order to get a basically functioning thing out the
           | door sooner and maybe fix the most-annoying warts later.
           | (Minimum Viable Product, anybody?)
        
         | adwn wrote:
         | > _Yes, it 's a great feeling when your code fits like a jigsaw
         | puzzle, but also more complexity = more code being executed.
         | Behind that RAII, behind that "operator=" and that "p = new
         | Struct", etc. there might be extra complexity for the sake of
         | developer's readability and comfortability. There is little or
         | no added value for the end user or the purpose of the program
         | itself._
         | 
         | 'Yes, it's a great feeling when your code fits like a jigsaw
         | puzzle, but also more complexity = more code being executed.
         | Behind that function call, behind that nested expression and
         | that "p = malloc(sizeof(*p))", etc. there might be extra
         | complexity for the sake of developer's readability and
         | comfortability. There is little or no added value for the end
         | user or the purpose of the program itself.'
         | 
         | See? The same argument can be used against C in favor of
         | assembly. Abstractions allow us to write safer, more correct
         | code in less time, which actually does offer a lot of added
         | value for the end user. C makes many useful abstractions harder
         | or downright impossible, which is _one_ reason why software
         | written in C is generally such a shitshow from a security
         | perspective.
        
           | scoutt wrote:
           | > Behind that function call, behind that nested expression
           | and that "p = malloc(sizeof(*p))", etc. there might be extra
           | complexity for the sake of developer's readability and
           | comfortability.
           | 
           | There is no way to avoid most of things you listed. It's not
           | comfort; it's a necessity.
           | 
           | > software written in C is generally such a shitshow
           | 
           | Whatever language you use to code, all your calls will sooner
           | or later pass through a function call, a nested expression or
           | a malloc()/free() call, somewhere in the huge stack of C code
           | your language needs, depends and relies on. There is no
           | escape. Basically, today your preferred language exists and
           | might be able to something just because C code exists.
        
             | adwn wrote:
             | > _There is no way to avoid most of things you listed._
             | 
             | Oh yes, there definitely is: There are no function calls,
             | nested expressions, or _malloc_ in assembly - those are
             | abstractions provided by the language and translated by the
             | compiler, for comfort, not necessity. In fact, you can
             | simulate all that in C itself: use gotos and an explicitly
             | managed memory area as stack, and manually transform nested
             | expressions into SSA form.
        
       ___________________________________________________________________
       (page generated 2022-05-11 23:01 UTC)