[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)