[HN Gopher] Repeat yourself, do more than one thing, and rewrite...
___________________________________________________________________
Repeat yourself, do more than one thing, and rewrite everything
(2018)
Author : bshanks
Score : 144 points
Date : 2023-03-14 13:25 UTC (9 hours ago)
(HTM) web link (programmingisterrible.com)
(TXT) w3m dump (programmingisterrible.com)
| strict9 wrote:
| > _"Don't Repeat Yourself" often gets interpreted as "Don't Copy
| Paste" or to avoid repeating code within the codebase_
|
| When I think of the most difficult to understand code I've come
| across it was probably written by someone who lives and breathes
| that interpretation of DRY.
|
| But it doesn't end with code comprehension. Extreme abstraction
| and countless files and components also lead to buggy and
| difficult to maintain code.
|
| It's easy to lose understanding of branches and business flow
| when abstraction exists in the extreme.
| qudat wrote:
| > When I think of the most difficult to understand code I've
| come across it was probably written by someone who lives and
| breathes that interpretation of DRY.
|
| Totally agree with this interpretation and why I wrote a recent
| article about it: https://bower.sh/anti-pattern
| strict9 wrote:
| Great article, particularly agree with the tests part. Sanity
| check tests (function doesn't throw an exception in common
| path) are essential but following all possible paths and
| verifying all outputs is the road to diminishing returns and
| subpar output.
| Spivak wrote:
| I call these frankenframeworks. The constant drive to DRY and
| reach the supposed nirvana of code being a DSL of pure business
| logic leads to more and more implementation details being
| shoved under the rug to deeper and deeper layers. But for some
| reason there's no foresight that any non-trivial change
| requires changing more than just the business logic and so you
| have to resort to bolting on config options, weird hooks,
| mixins, "concerns", and global state for no reason other than
| it's all you can do to reach down the layers.
| andorov wrote:
| DRY needs to be balanced with SRP (Single Responsibility
| Principle). You can legitimately have two functions that are
| exactly the same but they should not be DRY'd up if they are
| actually serving different purposes.
|
| The use cases will likely diverge in the future, and if the
| functions are DRY'd making changes will make introducing bugs
| from the calling code that you're not working on easy.
| Eventually the single function will likely have a lot of
| conditions in it, which is a red flag for this situation.
| ramesh31 wrote:
| >You can legitimately have two functions that are exactly the
| same but they should not be DRY'd up if they are actually
| serving different purposes.
|
| I use what I've come to call the "Rule of Three" here.
|
| The first time, don't even consider any kind of abstraction.
| Just do the thing.
|
| The second time, don't abstract yet. Repeat yourself, but do
| it in a way that will scale and make abstraction possible,
| while mentally noting how you _might_ abstract it.
|
| The third time, abstract it.
|
| Adhering to this, the vast majority of code will never reach
| that third stage, thus taming the complexity beast.
| getoffmycase wrote:
| Thanks for putting the process of what I did twice in the
| last two days into clear, coherent words and logic.
| pydry wrote:
| I usually phrase this as balancing against loose coupling.
|
| I've had bad experiences with the single responsibility
| principle. It sounds kind of right, but in practice
| "responsibility" is too vague and often surprisingly hard to
| agree on what is e.g. one responsibility vs. three
| responsibilities.
|
| By contrast, loose coupling is more objective and can (at
| least in theory) be measured.
| unethical_ban wrote:
| Back when I took a Comp sci course 16 years ago (shit) I was
| taught that a single function should try to fit within a
| screen. The idea is that breaking a task up into digestible
| steps would both harbor more readable code, self-documentation
| and code reuse.
| mcphage wrote:
| > The idea is that breaking a task up into digestible steps
| would both harbor more readable code, self-documentation and
| code reuse.
|
| Sometimes. Other times it means you need to jump around in a
| file (or jump between files, even) to understand what's going
| on.
| wizofaus wrote:
| Which is fine - any software of non-trivial complexity is
| going to require looking at the behaviour of multiple
| execution units, which may well be in different files. But
| if they're named sensibly and the dependencies are clearly
| maintained, the typical programmer is going to have a much
| easier time of "understand[ing] what's going on" than a
| single huge largely-unstructured blob of code. The moment
| you can't quickly see where a block starts and ends
| (without using IDE shortcuts) then the code has a
| readability issue.
| MrPatan wrote:
| Good idea, wrong metric. What should fit in a screen is the
| concept. If you take a big, hairy, complicated thing and just
| chop it into several functions that fit on a screen you have
| gained nothing.
| saulpw wrote:
| If you name the functions reasonably, and the functions
| don't interact except through arguments and return values,
| you have absolutely gained something.
| commandersaki wrote:
| Probably a good case for inclining: http://number-
| none.com/blow/blog/programming/2014/09/26/carm...
| thfuran wrote:
| Inlining is the compiler's job, not mine.
| rzzzt wrote:
| That's when you rotate the display to vertical orientation.
| justinator wrote:
| "big, hairy, complicated thing" is a code smell and you
| would consider doing something about it, before it becomes
| truly a monster. Breaking it up into its constituent parts
| may be the way to go, if only because my brain's CPU cache
| is about 8 bytes of faulty memory.
| vlunkr wrote:
| I've dealt with code like that, and often wrote it. It's
| incredibly hard to get right IMO. It's an intuition that you
| develop over years of trial and error, not an exact science or
| set of rules.
| a_c wrote:
| Your code is useless if no one is using it. If a tree falls in a
| forest and no one hears about it, it made absolutely no sound.
| Everything comes after that.
|
| Many programmers put cart before the horse by subscribing to
| tidbits of "best practice". Having people using it, you can think
| about making it right and fast, making the making of it right and
| fast. Then make the right people making it right and fast. And
| turtle all the way done from here.
| avgDev wrote:
| I found myself stuck in analysis paralysis and fear of not
| creating a perfect app. I became my worst enemy. My app was
| praised by VP, managers and staff using it, yet I saw it as a
| pile of garbage.
|
| Then I realized it doesn't have to be perfectly DRY, it could
| technically just be spaghetti. It isn't spaghetti but some things
| could be improved. While, better designed apps are easier to work
| with sometimes there are situation where it is impossible to
| create a formal design document, so you just need to 'send it'.
|
| The next iteration will improve many things, but if were to do
| those things initially the app would be in development for years,
| and now it is running a business.
| kitsunesoba wrote:
| With time I've progressively become less concerned with staying
| DRY, which perhaps counterintuitively has made it easier to
| avoid spaghetti problems. It's easier to keep things clean with
| a handful of near-duplicates that are tailored to the needs of
| their call sites than it is with a single trying to do
| everything.
|
| It's a bit more work to keep behavior consistent across
| duplicates but I'll take it if it means less untangling work
| for myself in the future.
| programmarchy wrote:
| I've found the same, and have leaned more into patterns and
| proximity as guides. Find good patterns that can be repeated
| easily and predictably. Also, keep related code close
| together so it's easy to find and copy somewhere else. Often
| times there are higher level abstractions that emerge which
| can then be "dry"ed out, but trying to do that too early
| creates more problems than it solves.
| toast0 wrote:
| Garbage that shipped and has customers and a purpose (and maybe
| makes money, if your company is interested in that) is called
| Legacy. Perfect code that never shipped doesn't have a name.
|
| Worst case, your garbage code gets you 6-12 months with
| customers and it has to be thrown away. No big deal, you said
| it was garbage _and_ now you 've got 6-12 months of actual
| knowledge of what your customers need and want, instead of what
| you thought they would need. You can make new legacy garbage
| that's much better than the first version now.
| BeetleB wrote:
| I've said it before and I'll say it again - I should encapsulate
| it as a law.
|
| BeetleB's Law of DRY: Every article that complains about DRY will
| be a strawman argument.
|
| The DRY acronym came from _The Pragmatic Programmer_ , and almost
| every instance of DRY people complain about is _not at all_ what
| is advocated in the book. There are different ways of
| interpreting what he wrote, but my version is: "If you have two
| separate requirements that are very similar, keep them separate
| in code. If your duplicated code is _one_ requirement, then DRY
| it into one location in your code. "
|
| So this:
|
| > Following "Don't Repeat Yourself" might lead you to a function
| with four boolean flags, and a matrix of behaviours to carefully
| navigate when changing the code.
|
| Is not DRY. In fact, having boolean arguments is almost a
| guarantee that you've violated DRY.
|
| Another way to know you've violated DRY: If one requirement
| changes, do I need to add if conditions to the DRY'd function to
| ensure some _other_ requirement doesn 't break? If yes, you're in
| violation.
|
| Never tie in multiple requirements into one function. Or rather,
| do it but don't call it an application of DRY.
| duxup wrote:
| Yeah I'm pretty burnt out on the DRY articles. It's so easy to
| misrepresent something as an absolute and talk about how it is
| wrong. As for DRY, it also means they don't understand / or
| aren't honest about what DRY is about and I immediately am
| skeptical about the author.
| BeetleB wrote:
| > As for DRY, it also means they don't understand / or aren't
| honest about what DRY is about and I immediately am skeptical
| about the author.
|
| Indeed - I didn't bother reading the rest of the article.
| noodle wrote:
| I personally agree with your point of view on what DRY is.
| But,I don't think that's what's being taught or talked about
| anymore. When people say DRY they usually mean an abstraction
| layer that merges two similar concepts into one, and the DRY
| you talk about is just standard operating procedures. Static
| analysis tools will ding you on DRY rules if you have code that
| looks pretty similar, urging you to refactor them to be the
| same. Etc..
| TeeMassive wrote:
| If most people "straw man" your position then it's not because
| they're straw manning your position but because they
| misunderstand your point because it is not clear enough.
| lightbendover wrote:
| I don't see how you can throw away the modern definition of DRY
| and put critiques of it (the modern definition) to bed just by
| pointing out the historical origination. They're completely
| different topics and the discussions thus need to be insular.
| BeetleB wrote:
| Then start your critique of DRY by pointing out there are
| multiple definitions of it, and that you are referring to one
| definition.
| Jtsummers wrote:
| They can't be meaningfully separated because they're using
| the same phrase with almost, but not exactly, the same
| meaning. One version having a sanity check (don't repeat the
| actual same logic/information, at least not excessively;
| usually it's paired with the "Rule of Three" which is three
| repetitions then look for a refactor) and the other not
| (don't repeat anything that happens to look alike and don't
| actually think, follow this rule like it's written in stone).
| If these aren't distinguished, then you end up with everyone
| talking past each other both thinking the other is an idiot
| (rightly from both perspectives).
|
| People arguing against the latter are making a sane and
| reasonable argument. And people arguing for the former are
| making a sane and reasonable argument. But if, in the same
| discussion, both senses are meant without qualification or
| clarification then only confusion will be found.
| strken wrote:
| If your catchphrase is Don't Repeat Yourself and some people
| take it to mean they shouldn't repeat themselves, the fault is
| entirely with the catchphrase you used.
|
| If a third set of people then take it upon themselves to tell
| everyone that Actually You Should Repeat Yourself Sometimes,
| this is not them attacking a strawman, it's an attempt to clear
| up the confusion caused by the phrase/acronym DRY.
|
| The original definition of DRY was "Every piece of knowledge
| must have a single, unambiguous, authoritative representation
| within a system." _That 's not what Don't Repeat Yourself
| means_, if read literally. Because DRY sounds like it applies
| to code instead of to knowledge, _of course_ it 's widely
| misinterpreted! If they'd called it the Fight Unnecessary
| Copying of Knowledge principle nobody would be having this
| argument and we'd all get to save ourselves a lot of time.
| klysm wrote:
| Doesn't matter what it originally meant, people take it to mean
| you shouldn't have repeated code and that's the DRY we all live
| with which results in bad abstractions. I don't think it's a
| straw man at all, unless you use your specific definition of
| DRY which isn't very useful
| BeetleB wrote:
| People are welcome to co-opt the acronym and give it another
| meaning. The issue is that the original DRY is a _damn good_
| principle, and it is more important to give it a name and
| propagate that knowledge.
|
| If all we do is rail against the "new" DRY and forget the
| original one, then we are at a net loss.
| wizofaus wrote:
| I'm with you - the violations of DRY I still see regularly
| are clear cases of copying and pasting _exactly_ the same
| logic (or magic literal value) when there was no reason not
| to put it in a helper function or named constant that could
| be referred to in both places. A code review I did
| yesterday had that - there were 5 or 6 lines of code that,
| starting with a particular regex, did some data massaging.
| It was determined in some cases a different reg-ex was
| needed for a second pass over the data, and so the
| submitter had simply copied the 5-6 lines of code and just
| changed the reg-ex used. I see that sort of thing 20 or 30
| times more often than code that gets itself into knots
| because of excessive abstraction trying to avoid code
| repetition.
| kqr wrote:
| To be fair, in your example it sounds like the repetition
| is very local and easily recognised for what it is. Not
| ideal, but hardly a poster child for when DRY is
| impactful.
|
| If the change was otherwise good, I would remark on the
| repetition as "here's how I would write it differently"
| and not "go back and fix it now".
|
| The first time someone changes four of the cases the same
| way but misses the fifth, though. That sounds like a good
| time to refactor.
| isleyaardvark wrote:
| I love the principle but do we want to save the principle
| or save the acronym? At this point IMO it's a lost cause. I
| wish someone with a following would make a retronym of TIE
| or SYNC to express it.
|
| I remember when The Pragmatic Program 20th Anniversary came
| out, the authors, in interviews and the new edition itself,
| described DRY as "the most misunderstood" concept in the
| book. If for 20 years that is the most misunderstood
| concept, then maybe the name is not the best.
| xahrepap wrote:
| I propose the following: DRBL - Don't Repeat Business
| Logic
|
| It's funny, because "dribble" or "drool" is the opposite
| of being dry ;)
|
| Although it doesn't have as fun of a pronunciation in
| English, DRBR is probably a better acronym? Don't Repeat
| Business Requirements
| mrkeen wrote:
| I feel exactly the same way about DI.
|
| Structuring code so that abstractions don't depend upon
| implementation details is in my top 3 principles of all
| time (along with pure functions and good typing).
|
| DI frameworks a la Spring and Guice just annoy me.
| rched wrote:
| The problem is with the entire concept of development
| "principles". They are a bad way to propagate knowledge. I
| suspect more people have an incorrect understanding of DRY
| than not. Seems like a net loss to me.
|
| We should ditch these principles altogether and focus on
| teaching a deeper understanding of these concepts that
| captures the nuances.
| BeetleB wrote:
| I don't think you can move away from principles in
| general. The reality is that most SW design is
| subjective. Not reusing code is a _generally_ good
| principle. It 's just that the misapplication of DRY is
| following one good principle but violating another one
| (requirements should be decoupled).
|
| In any case, the reason I go on the anti-rant rant each
| time is because when I use DRY appropriately, I don't
| want some idiot flagging me in a code review saying
| "Don't do this. DRY is bad. Here are N blog posts
| explaining why" - when none of the blog posts are
| complaining about what I am doing.
| rched wrote:
| I don't think you can separate the principle from its
| misapplication. It's misapplied because it tries to stuff
| useful knowledge into a memorable phrase and the nuance
| is lost.
|
| Flagging code in code review is another great example of
| harmful behaviour principles encourage. I've stopped
| referencing principles altogether in code review and I
| encourage others to do the same. Instead I focus on
| trying to explain the specific impact the code will have
| on our specific codebase.
| danielovichdk wrote:
| I think it's very useful
| smac__ wrote:
| Here, only apply Don't Repeat Yourself to data not code. Making
| it mean each piece of knowledge should have a single
| authoritative reference. E.G. Avoid (if possible) places where
| state is synced.
| pphysch wrote:
| That's a great way to summarize it.
|
| With the corollary that "hard-coded data" is still data, not
| code.
| mmcclure wrote:
| > If a replacement isn't doing something useful after three
| months, odds are it will never do anything useful.
|
| This is painful to read, but unfortunately rings true.
|
| As an aside, when I saw the domain name/year I thought I'd find
| an update to one of my favorite programming rants of all time,
| "programming sucks."[1]
|
| [1] https://www.stilldrinking.org/programming-sucks
| jonfw wrote:
| This is oddly comforting to read
| BoxOfRain wrote:
| That rant gets better every time I read it.
| Clent wrote:
| Ignore advice on what not to do.
|
| Listen to advice on how to accomplish tasks.
|
| A carpenter does not study how not to hang a door.
|
| Likewise, don't listen to advice on how not to write code.
| ParetoOptimal wrote:
| I don't think it's quite the same though... or at least I can
| make an argument for learning about ways not to do programming
| tasks because it generalizes.
|
| There are patterns between ways not to do programming related
| things, e.g. use the single responsibility principle, use pure
| functions.
|
| There are also so many ways to accomplish programming tasks,
| it's useful to be able to filter down that multitude of ways or
| notice "this stack overflow post has 5 bad patterns, maybe I
| shouldn't use it".
| [deleted]
| jrochkind1 wrote:
| I don't disagree with a single thing in the OP.
| foundart wrote:
| Lots of good ideas here, especially that duplication is better
| than the wrong abstraction.
| tpmoney wrote:
| One of the best pieces of advice I got really early in my
| career was write something 3 times before you decide to
| abstract it. Until you've done that, you just don't know what
| parts you can really abstract and you're likely wasting time.
| Pretty much every time I've ignored that advice I've regretted
| it.
| stametseater wrote:
| Same. Writing something more than once gives you more than
| one perspective on the problem space. And with a better
| understanding of the problem space, you're more likely to
| find an optimal solution.
| giraffe_lady wrote:
| aka WET: Write Everything Twice.
| jimmaswell wrote:
| > Never rewrite your code from scratch, ever!
|
| Is this really a common sentiment?
|
| When it comes to rewriting _others '_ code, it's prudent to keep
| in mind that it's naturally harder to understand code written by
| someone else. Just because you're confused in the first five
| minutes of looking at something doesn't mean it's an unsalvagable
| spaghetti. It's too easy to underestimate the time and cost of a
| rewrite and confuse your lack of knowledge for a fault in the
| codebase. Of course sometimes a rewrite is still appropriate
| after that consideration.
|
| If it's your own code then you probably have a better judgement
| than anyone whether it's in need of a rewrite.
|
| Doesn't everybody tend to rewrite major components of something
| in its early states? Though I find as I gain experience over the
| years I have to rewrite/"draft" code less and less.
| kitsunesoba wrote:
| Some of the most significant jumps in quality I've seen have
| been in total rewrites of my projects, at least when the
| project in question was at least moderately complex.
|
| There even used to be a project that I'd rewrite every so often
| (but never publish) just to see how much better each iteration
| was. That fell to the wayside because I got busy, but I should
| probably pick it back up at some point.
| rzzzt wrote:
| Do you keep the project runnable at all times when you
| rewrite? My issue is twofold:
|
| 1) You can not do anything with the pieces until they are
| back together
|
| 2) If everything goes well, you get to see the exact same
| behavior as before. It can be faster, easier to modify or add
| stuff, perhaps even more elegant on the inside, but it will
| still be the same application.
| kitsunesoba wrote:
| For #1, yeah I do. If I'm working on more
| routine/boilerplatey parts I might go a little longer
| without running, but it's pretty important to me to verify
| that each bit is working as expected before moving on. It's
| easy to wind up in a mess if I'm operating on the
| assumption that what's been written so far all works.
|
| For #2, yeah that's true, but for me less visible
| improvements are gratifying, because not only is the thing
| being rewritten being improved, but I can also apply
| learnings to other projects that make rewriting them less
| necessary. Also, it just bugs me when there's reasonable
| obtainable improvements in optimization, flexibility, etc
| that I've left on the table... feels like I left the job
| half-done which isn't a great feeling.
| colonCapitalDee wrote:
| Not the person you originally asked, but I have the same
| rewriting habit.
|
| Automated tests are essential for rewriting code. If I want
| to rewrite untested code I either add tests or don't
| rewrite it. The rewritten code also needs to be tested.
|
| Whenever possible, split up big, untestable rewrites into a
| series of smaller, testable rewrites. Let's say I want to
| rewrite component A with subcomponents B and C to use some
| new library Foo. I might first rewrite B to use Foo, then
| rewrite A (and A's tests!) to work with rewritten B. Then I
| rewrite C to use Foo, then rewrite A again to work with
| rewritten C. Then I finally go rewrite A to use Foo. This
| is more coding then doing the whole thing in one go (I
| rewrote A 3 times!), but it's a net time saver because when
| I make a mistake I can quickly find and fix it.
|
| When I'm on the clock I rewrite code for practical reasons
| (maybe the current structure of the code can't support some
| new requirement, or technical debt has gotten high enough
| to make maintenance difficult, or whatever). This is rare-
| ish. Rewriting code, especially production code, is risky
| and time consuming and just generally not worth it.
|
| Most of the time when I rewrite code I'm rewriting my own
| code, and I'm doing it for personal reasons. I like good
| code, I like reading it and I like writing it. To me code
| has aesthetic qualities, code can be beautiful and elegant.
| It's also educational. Imagine a writer that never edits
| their work; they're probably not a very good writer. It's
| also fun! I'm already familiar with the problem domain, so
| I can devote my entire focus to solving the problem instead
| of splitting my attention between solving the problem and
| figuring out wtf is going on.
| joevandyk wrote:
| https://www.joelonsoftware.com/2000/04/06/things-you-should-...
|
| "They did it by making the single worst strategic mistake that
| any software company can make: They decided to rewrite the code
| from scratch."
| sundarurfriend wrote:
| If you're not a programmer and are just stumbling around trying
| to code, ideas like DRY and abstractions and modularity are super
| useful. I work with scientists/PhD students helping with their
| code from time to time, and it's easy to forget how much basics
| we take for granted.
|
| If you're a career programmer or want to be one, then yes, it's
| better to try things out and figure out from experience _why_
| these principles exist. Then, you can break the rules, because
| you understand their purpose and limitations now.
| tabtab wrote:
| "Always do X" and "Never do Y" are almost always bad advice. Live
| by rules of thumb but don't become a zealot or rigid purist. Some
| duplication is acceptable, but lots is probably a sign that
| something is factored poorly or the wrong tool for the job.
|
| Rules of thumb include but are not limited to: KISS, YAGNI, and
| DRY.
|
| Another good rule of thumb is make things easy to figure out for
| future maintainers who you have yet to meet and may never.
| Programming is communicating with a future human, not just a
| machine. It's about people. (Insert Soylent Green jokes here.)
|
| At least in ordinary CRUD, I find that simple, re-composable
| mini-components get me far more reuse than big swiss-army-knife-
| like components. Small components that can be copied, tweaked,
| remixed, or ignored with ease are more flexible.
|
| Also, communicating via strings and string maps (dictionaries)
| makes them easier to mix and match than complex data
| structures/classes. String maps are relatively simple yet
| flexible for structure passing. You lose a little compile-time-
| type-checking by going string-centric, but there are work-
| arounds, such as optional named parameters that switch on type
| scrubbing when needed. (I love optional named parameters. Every
| language should have them.)
| bokohut wrote:
| I found the article to be sound in the fact of modularity and
| building upon what works as the old adage states "if it ain't
| broke don't fix it" holds true however there is always room for
| technology improvements when one monitors and measures the entire
| lifecycle of a transaction system. The world's systems exist in
| the way that they do today because someone took a risk on a
| design to work and the uptake of what "works" only spreads as the
| acceptance of said design is proven. I have wasted most of my
| adult life rewriting the same system in entirety five times and
| am now in the process of rewriting it again for the sixth however
| now I am applying it to a different industry. The design was
| proven over several decades in the critical uptime high
| transaction volume payments industry and now that same design is
| being generalized into other industries. The other industries
| applications may not have the same transaction volume
| requirements as the financial industries designs however
| refactoring what works ensures the critical availability portion
| as well as the scaling flexibility to meet potential high
| transaction volume should any other applied industries demand
| that same growth requirement.
| agentultra wrote:
| I think there needs to be a version of this for pure FP languages
| like Haskell or even OCaml or F#; almost none of these maxims and
| aphorisms seem to apply.
|
| Abstraction? It has a completely different meaning in this
| context. Our business is abstraction: creating precise
| definitions and semantic meaning where none existed before. It is
| much easier to create abstractions and sufficiently demonstrate
| their laws hold. So much so that we often design our programs and
| libraries with abstractions first.
|
| This forces our programs to deal with the side-effects of
| interacting with the world outside of our programs' memory-space
| at the very edges of our program. We can prove a great deal of
| our code is correct by construction which lets us focus our
| testing efforts on a much smaller portion of our programs.
|
| However even in non-FP languages I think a lot of these problems
| do go away if you use the above definition of _abstraction_ and
| spend a bit more time thinking about the problem up front before
| writing code. Not too much, mind you, because the enemy of a good
| plan is a perfect one; however enough that you know what the
| essential properties and laws are at least tends to help and
| reduce the amount of code you need to consider and write.
| avgcorrection wrote:
| FP has a better definition of abstraction where it is closer to
| the sense of "simplify".
|
| In procedural programming it might just mean _indirection_. Or
| silly metaphors.
___________________________________________________________________
(page generated 2023-03-14 23:02 UTC)