Monday, November 07, 2011

Programming definition: Fragile Code

I've seen variations of the programming term "Fragile Code" lying around but I thought I'd formalize it in a post so that other programmers can get an idea of what this means. For me fragile code is defined as follows:

Fragile Code: Code that is hard to service, modify or improve without introducing many bugs. Fragile code tends to rely on too many assumptions that quickly become no longer true a features are added.

Generally speaking fragile code is not discovered until a strange bug occurs that was caused by violation of one of the assumptions in the original fragile code. What makes fragile code dangerous is it makes time estimates increasingly difficult as a small feature ends up breaking the fragile piece of code despite it having no direct relation to the feature being added.

On the internet Fragile code is referred to as copy and paste code but I frequently find that too specific in fact some programmers in my profession I find write fragile code by nature because they can have access to the entire code base so they assume the contents of other classes and methods won't change.

How do you not create fragile code?

#1 Never trust the contents of methods always assume that anything inside a method may change the only thing you can rely on is the method name to indicate what the methods should do.

#2 Don't even trust yourself. Ok so you wrote a function and you know that you only call it with a non null condition. The problem is this assumption that you made quickly falls flat when working with a team. Other people modify your code and your original assumption that you can expect a certain call order I.E. function 2 will always be called after function 1 and therefore funciton 1 will make a class level variable not null is not a stable assumption.

There is a way around this however. If you absolutely need function 1 to be called before function 2 stick an assertion that says that. Assertions are NOT program logic they are programmer tools an assertion states the programmer's assumptions at runtime. If you are assuming something and you know you can't handle a situation where your assumption isn't true stick in an assertion. This will at least make your fragile condition easier to track down in the future.

#3 Never rely on call order. One type of fragile code is function call order reliance this is when a programmer creates utility functions func1() func2() func3() and they must be called in order func1() func2() func3() calling any one of these out of order will cause a failure. The problem is to an outside observer func1() func2() func3() look like independent functions and don't look like they have anything to do with each other so in theory they may think you can call func2() and it should be fine.

If you encounter this scenario you should either indicate the dependency through the method names or (preferred) have automatic function call dependency. I.E. add code so that if you detect func2() was called without func1() then have func2 execute func1. However it would be preferable that if you have this scenario to not expose the utility functions altogether.

No comments: