Live data from Hacker News

Never edit a method, always rewrite it?

dave.cheney.net

91–100 of 120 posts

Re: Never edit a method, always rewrite it?

#91
post #84

Earlier quoted context omitted.

Unit tests can only test certain kinds of behavior of the function under test. To give other kinds of examples, the current implementation might have used a clever trick to achieve faster execution (this cannot be evaluated with unit tests). Alternately, it might have been implemented so as to share common functionality with a different piece of code by calling a common subroutine. That sharing of functionality is pr…

The most "fun" subcategory of "how do I write a test for this?" that I've seen is when something in your software triggers a bug in somebody else's product, and "somebody else" is both too big and important to return your calls and too relied-upon for the bug to go unaddressed (e.g. the Oracles and Ciscos of the world). So you have little recourse beyond screwing around with your code until the user stops seeing the…

That happens all the time. I generally encapsulate the logic compensating for the bug and decorate it with copious comments explaining the rational then write a unit test explicitly testing for the buggy behavior. If the bug gets fixed then the test fails and the product doesn't ship until it's resolved.

Yes I write unit tests for 3rd party APIs and libraries I consume if they show themselves to be inconsistent or buggy.

We actually use a 3rd party API that crashes regularly and we have a suite of unit tests surrounding it so when reports come in we can isolate, reproduce, and verify the problem before bringing fury down upon the vendor.

It is also handy during pre and post deployment validation to ensure that the environment your update is working in is 100% functional. I've rolled back releases before because an external resource had an unreported outage that caused our deployment validation to fail. With pre/post test you can test the environment before you even start.

Re: Never edit a method, always rewrite it?

#92
post #61

Earlier quoted context omitted.

I'm not convinced of the "always rewrite" thing, but what you're talking about would be solved by writing tests when you fix a bug.

It's not the first time someone proposes to write a test when fixing a bug, but you have to question the actual ROI. At my previous job, they checked how likely it is for a fixed bug to reappear again. Odds are really low. So we decided it wasn't worth the investment to write a test specific for the bugs use-case, because it's unlikely to appear again. We focused our efforts to other, more effective things.

80% of all tests should not be written, or if already written: deleted. A test is only valuable when it fails alerting you to a change you made that introduced a bug. There is a catch though: I don't know which of those tests are valuable.

I find the ROI for tests is high despite the large number of worthless tests because of the ones that fail a small number alert me to something I wouldn't have found otherwise.

The 80% number was of course made up. In my experience it is realistic, but I have never done a formal study.

Re: Never edit a method, always rewrite it?

#93

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.

In some languages you can use property-based testing to generate thousands of inputs and check that Method(x) == OldMethod(x). See Hypothesis for Python, QuickCheck for Haskell, ScalaCheck for Scala, etc.

Re: Never edit a method, always rewrite it?

#94

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.

Funny, a modern day waterfall method example.

Re: Never edit a method, always rewrite it?

#95
post #45

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.

For some hairy stuff that require live data you can also reverse the practice: call both yet return the old one, and gather data in production before switching. Obviously this does not work for side-effectful methods (beware of caches!).

I'm interested in what fields you would use this methodology. Machine learning?

In most fields we have a sample of known input vectors, including edge cases, that map to known outputs. A unit test is enough to test these methods with different implementations.

Re: Never edit a method, always rewrite it?

#97

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. It has been my experience that rewrites from scratch typically lose all this tacit knowledge and re-implement the original bugs.

This is the central argument in this famous piece by Joel Spolsky:

https://www.joelonsoftware.com/2000/04/06/things-you-should-...

To wit:

"Back to that two page function. Yes, I know, it’s just a simple function to display a window, but it has grown little hairs and stuff on it and nobody knows why. Well, I’ll tell you why: those are bug fixes. One of them fixes that bug that Nancy had when she tried to install the thing on a computer that didn’t have Internet Explorer. Another one fixes that bug that occurs in low memory conditions. Another one fixes that bug that occurred when the file is on a floppy disk and the user yanks out the disk in the middle. That LoadLibrary call is ugly but it makes the code work on old versions of Windows 95."

Re: Never edit a method, always rewrite it?

#99

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. It has been my experience that rewrites from scratch typically lose all this tacit knowledge and re-implement the original bugs.

That's sort of the point of the suggestion, I think. If you always rewrite from scratch rather than edit, this sort of tacit knowledge won't get embedded undocumented and untested into the middle of a function.

This is sort of the great contradiction of software development. Untested legacy software is hard to work with. So should our focus be on how to work with legacy software or how not to create it in the first place? There's really no answer to that.

Re: Never edit a method, always rewrite it?

#100

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. It has been my experience that rewrites from scratch typically lose all this tacit knowledge and re-implement the original bugs.

Often people suggest rewriting a method because it's so complex and poorly understood that it can't be maintained as-is, and for a method like that, you're right, it probably can't be rewritten without inadvertently changing the behavior.

I think what is being proposed here is rewriting methods that people usually don't consider because they're basically okay. Maybe the name is a little weird now because the usage of the method has changed. Maybe two methods that used to do something different now do effectively the same thing. But everything is basically correct and readable, and people don't want to make a bigger change than necessary.

Personally, I think I lean towards more aggressive rewriting than other people do. I try to make sure names make sense. When special cases are removed I check to see if this allows me to make the rest of the code simpler. When I see the same thing being accomplished in different ways in the same file, I'll take a minute to make it consistent, so that same things look the same.

But people see this as a trade-off, especially when it comes to code review. Several times when I've made major changes that needed to be code reviewed, I've taken extra time to re-order my commits so the change can be reviewed in two steps, first reviewing the refactoring that was done and then reviewing the change that was made. And with a single exception nobody has taken me up on it; they've insisted on reviewing the entire change at once. Instead of a straightforward refactoring and a straightforward change in functionality, now they're trying to make sense of a combination of behavior-preserving and behavior-altering changes. Because code gets reviewed that way, people tend to refactor less than is optimal, because they want to give their coworkers small diffs that highlight the logical change that was made. This is a tendency that can lead to a gradual accumulation of history in the form of duplicated code and nonsensical names, which I think is what the "rewrite every time" rule is meant to counteract. A technical rule won't make people forget a social trade-off, but it might help them remember the other side of the trade-off.

Post reply on HN