It has been my experience that after a substantial period of being in real use, methods embody tacit knowledge about the problem domain that isn't necessarily evident from their public interface. Because initially they didn't embody that, and it caused bugs, so people edited in fixes.<p>It has been my experience that rewrites from scratch typically lose all this tacit knowledge and re-implement the original bugs.
A tangential thought but related: I would find this absolutely frightening. I understand the motivation behind it but I always like to start from something existing and editing it -- even if by the end nothing remains of the original. To some, an empty editor window is infinite possibility but to me, it's a "coders block", not sure how to phrase it. Infinite analysis paralysis perhaps.
The headline is misleading IMO. The author is proposing “Never rewrite a method” _as a thought experiment_ to guide you to writing better code. Even the original proponent walked back from that idea moments after he proposed it.
I've been doing something similar. I name the new method Method, rename the old one as MethodOld and in Method, before the return value, I put an assert(MethodOld(args) == return value). It's one of the things that when I do, I appreciate the value of, but I'm not disciplined enough to do as much as I would like to lol.
When writing functions often I end up deciding fairly quickly if the function I am writing is intended to be reusable or not. If it is reusable I'll write it as a utility function, helper, lib, ... whatever the project's convention and language paradigm might be. Usually similar reusable functions already exist within the project.<p>A significant portion of functions fall in another category; functions that actually get some real work done. They are specific and not intended for reuse at all.<p>Applying the "never edit a method, always rewrite it"-rule to those helper/utility functions would just be painful. The public API you designed is designed with a certain purpose and reuse intent. Improving it slightly to fix an issue and forcing yourself to entirely rewrite it would just break things. Most likely you'll end up writing lots of small copies of the original method (how painful this exactly might be depends on the language you're using).<p>Applying that rewrite-rule to specific functions/methods makes slightly more sense. Here the logic is more tightly bound by business rules/logic, which if they change will quite often warrent a rethink. Particularly because business likes to just slap a feature on top of everything else; which means for us finding ways to keep everything sane in the codebase requires continuous refactoring. Rewriting a function here does not intend to make the function more reusable, it attempts to make the code more clear. Sometimes reusable patterns emerge, but often they don't.<p>Obviously the above is a simplification of things. Often programmers are obsessed with abstractions and design patterns (read too much GoF, Martin Fowler & Uncle Bob); or don't bother with anything at all (script kiddies, prototype developers, or any code written during a PhD...). The truth lies somewhere in the middle.
The metaphor that biological systems undergo continuous renewal and so therefore code should be rewritten not edited i think is actually off, code is the dna and thus undergoes evolution not replacement
A big part of what this approach is trying to fight is function complexity. If you really re-wrote the entirely of your functions everytime you went to edit them I think it would end up slowing the programmer and the program down.<p>Programming is often a state of flow where you have a grand idea for how a mechanism should act and then you task yourself with implementing that idea in code. Sometimes large complicated functions are the best way to translate that idea. The approach the author describes sounds like it would create lots of small functions that don't really help you solve the problem at hand.<p>Good idea to keep in mind though. Everytime you go to edit a function and find yourself dreading it, maybe it's time to rewrite that one.
Devils advocate:<p>If you make this a strict requirement for your code base people write wrappers all the time, which creates a huge mess:<p><pre><code> def newMethod(x):
if x*2 == 42:
return 36
return oldMethod(x)
</code></pre>
You cannot enforce the requirement anyway, because people will just copy-paste the code and edit it under a new name.<p>You just cannot push this methodology unto developers.
I had a similar idea some time ago, that all the code should be write only. That is, you should always write new functions (and give them new names) instead of trying to rewrite them (if the spec changes, this assumes they were correct in the first place).<p>I think it's only really doable in purely functional language (like Haskell), though. It sort of means versioning of individual functions, and also types. It's very similar to rebinding values only as opposed to modification of variables.<p>But naming is a problem. Maybe.. There are two kinds of names of types and functions - intrinsic and extrinsic. Intrinsic name only describes what the thing is (e.g. array.search()). Extrinsic name relates to the problem being solved (e.g. product.findByPrice()). Maybe the functions (and types) that have only extrinsic names should be versioned and short name should be assigned to the latest version.<p>All in all, I think it's a concept worth researching.
Coming from EE, I like the thinking behind this. Components are similar to functions, they are tested to the nth-degree out of inventory, liability, and other concerns, and everything goes along well enough.<p>What would really help for that style of development would be a sort of <i>apropos</i> feature for your own code where you could look up methods by keywords rather than just identifiers. For larger projects, having people re-write several variations of what is basically the same method can be a problem even with mutable code. Perhaps Knuth's <i>literate programming</i> would help?<p>edit: And I bring <i>apropos</i> up because if you break things down into very small functions, and you don't have that, you end up writing several invariants of the same function because you can't find the one you're looking for.
N.B. This is not advice! The headline reads like advice, but if you read the article it's a "what if..." exploration to get you thinking.
If only business requirements, specs and use cases didn't evolve.<p>For our Christmas campaign, calculateCostOfGadget() needs to account for the compounding discount. Preferably yesterday, as we need to complete this month's billing to make payroll.
Usually when I want to simplify something I do a copying garbage collection of code. Manually shifting the good stuff from the old version to the new version, this means all code gets reviewed, and poor code gets left behind.
I had a different rule, which I was advocating for PHP 5.3 back in the day:<p>Have functions take regular parameters and the last one will always be an associative array of options.<p>This matches how functions evolve. You have some required parameters, then introduce more but the old callers don't know about them so they're optional.<p>I was trying to argue that PHP could unify the function call syntax and array definition syntax to encourage this. In other words the options would actually be virtual, as the caller would just supply the optional named parameters at the end of the function.
Well, just ask a perl dev ;-)<p><a href="https://en.wikipedia.org/wiki/Perl#Criticism" rel="nofollow">https://en.wikipedia.org/wiki/Perl#Criticism</a>
This is an interesting thought experiment.<p>Following the rewrite-not-edit method rule forces one to either sink or swim. And the only maintainable way to swim is to write small focused orthogonal methods that do one thing only. Otherwise, it is impossible at any scale to follow rewrite-not-edit.<p>I like take on different perspectives like this. Doing so ensures one thinks about how to design and what to code before simply diving in.
Perhaps the "Second system effect" would not apply if methods are kept small, but is a method really a good unit of work for these kinds of ideas? Better rewrite units, classes, whatever can be isolated/encapsulated in a meaningful way.
I’m not sure rewrite is the right word here. Always write a new version from scratch, use a different namespace, and never delete old code is a better idea. You can’t cause regressions if you never change old code that’s in use.
What if we did this (where methods are immutable) and also architected a runtime to do this? Also we would use our source control to operate on functions instead of files? All methods would have a UUID and a hash of the contents .
Looks like businesses have finally caught on to developers' obsessions with constant product rewrites and started saying "no."<p>So now we come up with this technique as a way to get our fix to rewrite everything from scratch.
This is actually the APL way. You make the language so high level and dense that even complex methods are one-liners. When you need to update it, you rewrite it. APL people have been screaming this for years.
I understand the sentiment behind this, but in practice this is going to be a terrible idea, in my opinion. I can imagine the codebase littered with method1, method2 kind of edits all over quickly.
how is that different to writing a test for the old method then writing the new method from within the test then moving it to the old location when you're finished.
Saw the headline, first though "I'll bet this is about dynamically typed languages", and lo and behold<p>> At a recent RubyConf...<p>EDIT: just wanted to add that when I code in dynamically typed languages I'm inclined to do the same thing. Without rigidity provided by a strong type system it's too easy to mess things up. That's why I prefer strongly typed languages so I can benefit from the structure they enforce.