views:

179

answers:

6

Assume i have a function in a code library with a bug in it i've found a bug in a code library:

class Physics
{
    public static Float CalculateDistance(float initialDistance, float initialSpeed, float acceleration, float time)
    {
        //d = d0 + v0t + 1/2*at^2
        return initialDistance + (initialSpeed*time)+ (acceleration*Power(time, 2));
    }
}

Note: The example, and the language, are hypothetical

i cannot guarantee that fixing this code will not break someone.

It is conceivable that there are people who depend on the bug in this code, and that fixing it might cause them to experience an error (i cannot think of a practical way that could happen; perhaps it has something to do with them building a lookup table of distances, or maybe they simply throw an exception if the distance is the wrong value not what they expect)

Should i create a 2nd function:

class Physics
{
    public static Float CalculateDistance2(float initialDistance, float initialSpeed, float acceleration, float time) { ... }

    //Deprecated - do not use. Use CalculateDistance2
    public static Float CalculateDistance(float initialDistance, float initialSpeed, float acceleration, float time) { ... }
}

In a language without a way to formally deprecate code, do i just trust everyone to switch over to CalculateDistance2?

It's also sucky, because now the ideally named function (CalculateDistance) is forever lost to a legacy function that probably nobody needs, and don't want to be using.

Should i fix bugs, or abandon them?

See also

+2  A: 

I once fought for a number of days with some MFC code that was behaving in an entirely unexpected way. When I finally figured out it was an error in the Microsoft supplied library, I checked the knowledge base. It was documented as (approximately) "this is a known bug we found 2 OS versions ago. We aren't fixing it because someone is probably depending on it".

I was a little mad...

I'd say that you should deprecate it. If you're upgrading the library your code depends on, you should test the code with the new library. If it's legacy code, then there's a known configuration it works on. Advise your users and move forward...

Kendrick
+1 for understatement. ;-) I've been more than a little mad in similar situations myself.
RBerteig
+1  A: 

As you aready described, this is a tradeoff between satisfying two different user groups:

  • Existing users who have build their software based on a bug in your library
  • New users who will be using your library in the future

There is no ideal solution, nor do I think that there is a universal answer. I think this depends entirely on the bug and function in question.

I think you have to ask yourself

"Does the function make any sense with the currently existing bug?"

If it does, then leave I'd it in the library. Otherwise, I'd probably toss it out.

Adrian Grigore
How would you answer that question in this (contrived) practical example? (*i guess it would have helped if i pointed out the error in the formula itself.*)
Ian Boyd
+2  A: 

Good question. I'm looking forward to some other answers. Here's my 2 cents on the issue:

Generally, if you suspect that many people indeed rely on the bug, then that's an argument for not fixing the bug and instead creating a new function CalculateDistance2.

On the other hand, and I think that's the better option, don't forget that people who rely on the bug can always continue using a specific, older version of your library. You can still document the removal of the bug (and therefore the modified behaviour or your library function) in the release notes.

(If your class happens to be a COM component, the conventional wisdom would be to create a new interface ICalculateDistance2 that makes the original interface obsolete, but preserves it for backwards compatibility.)

stakx
Well in COM we would have an `IPhysics` interface, with all the methods. And the rule is that if you want to change the interface then thou shalt create a new interface `IPhysics2`.
Ian Boyd
+2  A: 

Another option is to fix the bug, but leave the old code around as a LegacyCalculateDistance method that's available if anybody really needs it.

You could even implement the ability to select the "legacy" implementation based on (for example) a configuration file or an environment variable setting, if you're concerned about offering a compatibility solution to users who may not be able to make code-level changes.

David Gelhar
+1  A: 

Just for the sake of argument, let's assume your hypothetical language was C++ (even though it looks a lot more like Java). In that case, I'd use namespaces to create a fork that was (reasonably) easy to deal with from a viewpoint of both new and legacy code:

namespace legacy {
class physics { 
    Float CalculateDistance(float initialDistance, float initialSpeed, float acceleration, float time)
    {
    // original code here
    } 
}
}

namespace current { 
class physics {
    Float CalculateDistance(float initialDistance, float initialSpeed, float acceleration, float time)
    {
    // corrected code here
    } 
}

From there you have a couple of options for choosing between the two. For example, existing code could add a using directive: using legacy::physics;, and they'd continue to use the existing code without any further modification. New code could add a using current::physics; instead, to get the current code. When you did this, you'd (probably) deprecate the legacy::physics class, and schedule it for removal after some given period of time, number of revisions, or whatever. This gives your customers a chance to check their code and switch over to the new code in an orderly fashion, while keeping the legacy namespace from getting too polluted with old junk.

If you really want to get elaborate with this, you can even add a version numbering scheme to your namespaces, so instead of just legacy::physics, it might be v2_7::physics. This allows for the possibility that even when you "fix" code, it's remotely possible that there might still be a bug or two left, so you might end up revising it again, and somebody might end up depending on some arbitrary version of it, not necessarily just the original or the current one.

At the same time, this restricts "awareness" of the version to be used to one (fairly) small part of the code (or at least a small part of each module) instead of it being spread throughout all the code. It also gives a fairly painless way for somebody to compile a module using the new code, check for errors, switch back to the old code if needed, etc., without having to deal directly with every individual invocation of the function in question.

Jerry Coffin
And in no time at all, version **V287_23_8A_2::physics** will be released. At which point yourclient base will be totally confused, upset and looking to replace both you and yourcode.
NealB
@NealB: This is a way of dealing with breaking changes to a library. If you're breaking your library often enough for a version number like that to make sense, **that** is what's going to upset your customers (with good reason). What I've outlined above won't prevent all possible problems (especially from the complete lack of quality assurance you apparently advocate), but it isn't the cause of those problems either.
Jerry Coffin
+3  A: 

You'll never succeed at catering to every existing project using your library. Attempting to do so may create a welcomed sense of predictability, but it will also lead to it being bloated and stagnant. Eventually, this will leave it prone to replacement by a much more concise library.

Like any other project, it should be expected to go through iterations of change and rerelease. As most of your current user base are programmers that should be familiar with that, change really shouldn't come as a surprise to them. As long as you identify releases with versioning and document the changes made between, they should know what to expect when they go to update, even if it means they decide to stay with the version they already have.

Also, as a possible new user, finding your library to have an ever-growing number of lines of legacy code due to the blatant unwillingness to fix known bugs tells me that the maintainability and sustainability of the project are both potentially poor.

So, I would honestly just say to fix it.

Jonathan Lonowski