Live data from Hacker News

Never edit a method, always rewrite it?

dave.cheney.net

111–120 of 120 posts

Re: Never edit a method, always rewrite it?

#111
post #84

Earlier quoted context omitted.

You're not wrong. In theory if every time a fix was implemented, a corresponding unit test was created then you should be able to adequately test the rewritten method. I say in theory though because that never happens.

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…

Alternately, if it uses a regular expression or other form of pattern matching, it's very likely that the original coder made unit tests for the most common behaviors, but built in assumptions for edge cases. And I'm unaware of any code coverage tools that help someone test every single branch in a regex. So you're reliant on comments, documentation, etc. (thank goodness for Python's verbose regex mode, for example) to make those assumptions explicit. It's not an easy problem to solve.

Re: Never edit a method, always rewrite it?

#112

Earlier quoted context omitted.

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 bu…

s/unit tests for 3rd party APIs/ => /acceptance tests for 3rd party APIs/

Re: Never edit a method, always rewrite it?

#113

Saw the headline, first though "I'll bet this is about dynamically typed languages", and lo and behold > At a recent RubyConf... 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.

Don't confuse static/dynamic typing and weak/strong typing. A language can be both dynamically and strongly typed (Python, for example). The thing you like about a "strongly typed language" is the static typing, meaning a variable's type can't change once it's been created.

Re: Never edit a method, always rewrite it?

#114

Earlier quoted context omitted.

We use the test as a way to prove we know what the bug actually is. Our debugging "path" normally is: 1. Find out bug exists 2. Write a test that can reproduce the bug 3. Distill that test down to the minimum needed 4. Fix bug until test passes 5. Test bug is actually fixed by trying to reproduce it the same way the user/bugreport did. When done like that, the test isn't "extra work" but is just part of narrowing dow…

Whist I agree with this approach, sometimes it just isn't possible if the code was written in a non-testable way to begin with. Such as code that hits the database a lot or relies on network data. In this case, weighing up the ROI is a worthwhile endeavour, with a note to refactor more thoroughly at a later date.

> Such as code that hits the database a lot or relies on network data.

well the first problem is not a problem since you can cheat it. if you rely on the native database you can actually fake your driver and insert transactions (subtransactions or in postgresql savepoints) so for the whole test suite you just rollback to the latest savepoint, this saves a lot of time. (it's actually not that hard in java+di or in languages where you can monkey patc code.

Re: Never edit a method, always rewrite it?

#115
post #45

Earlier quoted context omitted.

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.

An example of when you might use this is when you're cutting over to a new service, and you want to validate that the new service behaves the same way as the old one before transitioning all the traffic to the new service. In order to build confidence in the new service, you can assert that the expected output is the same, and raise alerts when there is an inconsistency. This incremental rewrite approach allows you to slowly replace pieces of an application with a new service and helps prevent regressions in behaviour.

Or consider when you're performing a database migration (on large databases) with 0 downtime. Typically this involves something like:

1. Dual Writing: Create 2 tables and write to both and keep them in sync (by duplicating new data, and back-filling old data)

2. Update read paths: Change all code to read from the new table, and validate that the data being read is consistent with the old table. You can use a library like Scientist [0] to validate that the reads are the same.

3. Update write paths: Change all code to write to the new table (and raise alerts if the old path is exercised)

4. Deleting old data: Remove code and data that relies on the old data model

[0] https://github.com/github/scientist

Re: Never edit a method, always rewrite it?

#116
post #111
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…

Alternately, if it uses a regular expression or other form of pattern matching, it's very likely that the original coder made unit tests for the most common behaviors, but built in assumptions for edge cases. And I'm unaware of any code coverage tools that help someone test every single branch in a regex. So you're reliant on comments, documentation, etc. (thank goodness for Python's verbose regex mode, for example)…

A gray-box fuzzer such as american fuzzy lop (https://en.wikipedia.org/wiki/American_fuzzy_lop_(fuzzer) ) can generate quite good test cases. If your regex engine can compile to native code, it can generate tests that test every single branch of the regex.

Re: Never edit a method, always rewrite it?

#117
post #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…

Do two pull requests: one pure refactor, one pure logical change. I've been doing this at work, and it's great!

Re: Never edit a method, always rewrite it?

#118

Earlier quoted context omitted.

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 bu…

Those are all fine things to do if you can afford them. In my case, I'm talking about bugs that come sturdily packaged in a $5000+ chassis sitting on a private VLAN in somebody else's building. So it goes.

Re: Never edit a method, always rewrite it?

#119

Earlier quoted context omitted.

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.

An example of when you might use this is when you're cutting over to a new service, and you want to validate that the new service behaves the same way as the old one before transitioning all the traffic to the new service. In order to build confidence in the new service, you can assert that the expected output is the same, and raise alerts when there is an inconsistency. This incremental rewrite approach allows you t…

I see, thank you.

Re: Never edit a method, always rewrite it?

#120

Earlier quoted context omitted.

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.

Furthermore to Klathmon, there is an opportunity cost. Because you don't have the test, changing that method in the future becomes problematic. Is not the bug reappearing, is the refactoring that cannot longer take place.

In practice, the rewrites that I have seen, are not limited to just function bodies, without changing interfaces and class structures.

What I see in refactoring is that whole blocks of code get an overhaul. And in that case, all the test you wrote on those interfaces need to be adapted, rewritten or removed.

So actually, in a proper refactoring, some tests might help you out, because the interface of the classes didn't change. But other tests cost you time.

It's all a pretty complex balancing act. Some tests save you time, some cost you time. They all make the code more stable, but you have to put your effort where it really makes sense.

Post reply on HN