My approach is similar to this, except for whole functions/classes I tend to just create a new one with a version number. e.g. DataContext => DataContext2.
When I'm satisfied that DataContext2 does everything that DataContext does, I delete old one and rename DataContext2 => DataContext.
The risk here, is that sometimes it's not possible to migrate everything to the new version and you end up with multiple old versions lying around, i.e. technical debt.
I do the same, but the opposite way, hehe - I rename e.g. "DataContext" to "DataContextOLD1", then I write the new "DataContext" (from scratch or by copying the original one and then modifying it), this way I'm sure that all calls to DataContext always use the new version.
I do this too! A big benefit is gradual migration - for example, if I'm injecting DataContext into a bunch of different places, I can implement part of the functionality of DataContext. Once I have just enough functionality implemented to support one of the places it's injected, I update that place to take DataContext2. Then I can test, and move on to the next place.
If you're using a language with strong typing and good refactoring support (right now that's C#/Visual Studio for me), the eventual rename from DataContext2 to DataContext is a non-event.
When I'm satisfied that DataContext2 does everything that DataContext does, I delete old one and rename DataContext2 => DataContext.
The risk here, is that sometimes it's not possible to migrate everything to the new version and you end up with multiple old versions lying around, i.e. technical debt.