Agile FAQs
  About   Slides   Home  

 
Managed Chaos
Naresh Jain's Random Thoughts on Software Development and Adventure Sports
     
`
 
RSS Feed

Recent Thoughts
Tags
Recent Comments

Archive for the ‘legacy code’ Category

What heuristics do you use to decide Long Method Smell?

Friday, March 25th, 2011

I find myself using the following heuristics:

More details: Long Method Smell: When is a method too big?

Big Upfront Test Creation in Legacy Code is a Bad Idea

Wednesday, March 9th, 2011

When confronted with Legacy code, we usually run into the Test-Refactor dilemma. To refactor code we need tests, to write tests, we need to refactor the code.

Some people might advise you to invest time upfront to create a whole set of tests. Instead I recommend that every time you touch a piece of legacy code (either to fix a bug or to enhance the functionality), you perform a couple of safe refactoring to enable you to create a few scaffolding tests, then clean up the code (may be even test drive the new code) and then get rid of the scaffolding tests.

Even though this approach might appear to be slower, why does this approach work better?

  • You start seeing some immediate returns.
  • On any given system, there are parts of the system which are more fragile and needs more attention than others. There are parts of code which we actively touch and others we rarely touch. When we have a limit time, it does not make sense in investing effort to create tests for areas that are fairly stable or rarely changed. Big upfront test creation might not take this aspect into account. So you might not get the biggest bang for your buck.
  • The first few tests we usually write are fragile tests. But we won’t get this feedback nor the opportunity to improve the quality of our tests until its too late.
  • When we get into a test creation mode, everyone is focusing on creating more and more tests. Finally when we start using the tests we’ve created, a small change in production code might breaks a whole bunch of tests. First few times developers wonder what happened, but if this generates a lot of false-negative (which usually they do), then developers start ignoring or deleting those tests. So the investment does not really pay for itself.
  • Also when we have a whole lot of tests prematurely written, they start getting in the way of refactoring and genuinely improving the design of the code. (Defeats the whole point of creating test upfront so we can refactor.)
  • People get too attached to the tests they had written (it was a big investment). They somehow want to make the test work. People fail to realize that those fragile tests are slowing them down and getting in their way.
  • Unless the team gets into the habit of gradually building better test coverage, they will always play the catch up game with requirements constantly changing. (Remember we are chasing a moving target.)
  • Its usually hard to take a fixed (usually long) duration of time off from CRs and bug fixes. People will be forced to multi-task.

I encourage you to share your own experience.

    Technical Debt

    Wednesday, February 16th, 2011

    Technical Debt is any technical issues slowing down the project due to hasty (short-sighted) decisions made at an earlier point.

    All of us make bad decisions, but not fixing them and just differing them really leads to bigger problems as these issues have a snowball effect.

    Technical debt can be introduced at various levels:

    • Code smells is the most obvious one,
    • But things like lack of (or poor) automation,
    • poor choice of tools,
    • fragility in the development environment
    • and so on

    can also contribute to technical debt.

    Rewrite v/s Refactor Dilemma

    Tuesday, December 22nd, 2009

    A lot of developer have a tendency to suggest rewriting legacy code instead of refactoring. Personally I don’t think one approach is better than the other. Following are the issues/issues one needs to consider with each:

    Rewrite:

    • Difficultly in coming up with Cost and Time estimate. (Its best to pull some numbers off the hat)
    • What if new bugs are introduced during rewrite?
    • Similarly how do you avoid unintentional behavioral changes?
    • What is the guarantee that you won’t end up with the same problems?
    • How do you get Management buy-in? Let’s say even if you get Management buy-in, how do you motivate developers to rewrite existing apps?
    • While rewriting, we’ll certainly introduce new technologies. How do you deal with problems introduced by new technology?
    • How to handle change requests during rewrite?
    • How to avoid not over engineering the solution?
    • How do you deal with various Political Issues around technology, tools, team, etc.?
    • How do you avoid Resume Driven Development?

    Refactor:

    • How do you deal with Refactor-Test Dilemma (Egg and Chicken problem) ?
    • How do you motivate the existing team to continue and refactor code?
    • How do you effectively identify the inflection point?
    • How to avoid big changes (in the name of refactoring) instead of baby steps?
    • It takes quite a lot of time and effort to understand legacy code
    • Even while refactoring developers might have a tendency to over engineer (esp. coz most developers conclude that the original developers did not think well and build an extendable solution)
    • To Refactor effectively it certainly need developers with higher skill-set. Can you find them?
    • Many times you’ll run into difficultly in breaking dependencies. How would you deal with it?

    In my experience a thin-sliced hybrid approach seems to work the best both from technical and business point of view. In a subsequent blog I’ll explain what I mean by thin-sliced hybrid approach.

    Long Method Smell: When is a method too big?

    Wednesday, August 20th, 2008

    Unfortunately most people still measure size of code in number of Lines of Code (LoC). We all know LoC is a professional malpractice. Now, how do you objectively identify a long method? If we are not supposed to count LoC, then how can we define a long method?

    Some people say, if the code does not fit in one screen and if you have to hit page down, then the method is long. How many times have you looked at code that fits in one screen, but still felt that code was long? Happens to me all the time.

    Joshua Kerievsky says “If one cannot quickly and easily understand what a method does and how the method does it, it is a long method”. I really like this definition. But is a little wage to me and I don’t quite understand the theory behind why and when can something be hard to easily understand.

    One approach I’ve found to rationalize long method smell is by using the Single Responsibility Principle (SRP). If the method violates SRP, there is a good chance that its Long Method.

    If I need to parse the method’s code more than once, then its a good indication that the method is complicated to understand.

    Cyclomatic  Complexity can also give some interesting data points to under/measure when a piece of code is long. Usually large methods have a higher CC.

    Recently I stumbled upon ”The Magical Number Seven, Plus or Minus Two: Some Limits on Our Capacity for Processing Information“, a 1956 paper by the cognitive psychologist George A. Miller of Princeton University’s Department of Psychology.

    In this paper, Miller showed a number of remarkable coincidences between the channel capacity of a number of human cognitive and perceptual tasks. In each case, the effective channel capacity is equivalent to between 5 and 9 equally-weighted error-less choices: on average, about 2.5 bits of information. – Source WikiPedia

    What does this mean? In a layman’s world, this means that 7+/-2 is the number of things (concepts) we can hold in our brain. So when I look at a piece of code and if it has more than 9 things in there, it exceeds my brain capacity to hold it in my memory and actually understand what is going on. I often notice that 7 or less things in the code is easy to manage. Once it starts cross that number, its gets exponentially difficult to hold it in my mind and to understand what is going on.

    So if you are thinking of deleting elements from an array if they match a set of to-be-deleted elements, then that’s a good method for me. Why? Coz : I have an array, a set, an iterator, a loop, current values, a comparator and a delete operation. Around 7 things. That’s the max I can hold in my brain. But now if all of a sudden you throw thread synchronization into this, I may end up taking the loop, matching the current elements and the deletion out into another method.

    So size has nothing to do with LoC, its a measure of related concepts that you need to hold in your brain.

        Licensed under
    Creative Commons License