5

In this blog post, the author describes an anti-pattern called the "lava flow"

In a nutshell, the lava flow anti-pattern happens when many programmers lead the development of an application, each of them trying to gradually change the technology the said application is using.

Here's a summary of the situation the blog post describes:

  • Laurence starts the development of the application with the technology A
  • Laurence finds another job, Bruce comes in. He tries to convince the management that technology B is better. He asks for time to be allocated for refactoring. But due to budget and time constraints imposed by the management, he ends up writing new code with technology B, and tries to refactor – bits by bits – the old code from technology A to B.
  • Bruce finds another job, Ina comes in. She recommends technology C, ...
  • and this goes on over and over again.
  • At the end, the application is using technologies A, B, C, D, E, F. Because each programmer added their new technology, and tried to refactor the legacy code, but not all of it.

My question is the following, imagine what should have Bruce (the second programmer done) ? What is the best practice here? I understand that this depends on the situation, the technologies involved, and other factors... But is there a good rule of thumb?

Should you embrace legacy code? Should you block the development process, and say "I can't do anything without any refactoring"? Is the lava flow anti-pattern not so bad after all?

  • One reason to hire more than one programmer even if it's just part-time. And when you refill the position, clearly state the technology stack and the unlikely chance it will change. – JeffO Mar 13 '15 at 14:42
  • The tension always exist because there is always some misalignment between corporate interests and an individual's career interests. The stone is cold, the lava is hot (and flowing), therefore lava flows over the stone (and the stone can't stop the lava) until one day the lava cools down and become a stone. (Pun or rhyme *not* intended.) – rwong Mar 13 '15 at 16:14

3 Answers3

10

I think your summary have over-simplified the blog post somewhat. :p I'm going to pick out three sentences, which I think is crucial as to explaining why code became... lava.

The code gen system had somewhat broken down after Bruce had left. None of the remaining team really understood how it worked, so it was easier just to modify the code by hand.

Lesson #1: The team needs to fully understand how the things work. If Bruce is a bad educator, address that (probably from management), not to work around the code through "modifying it by hand".

She asked Simon what to do. “Yeah, I think that code was written by some guy who was here before me. I don’t really know what it does. Best not to touch it in case something breaks.”

Lesson #2: Write tests. Let the tests break to sound out that someone's assumption is/was wrong, and then address that. On a related note, don't be afraid to refactor or even modernize the code. Just make sure that safeguards are in place to make it explicit when "things break", before the code goes into production.

Ina, frustrated by management who didn’t understand the difficulty of maintaining such horrible legacy applications, left for a start-up where she would be able to build software from scratch.

Lessons #3 and #4: You need buy-in from the management, and don't adopt a Not Invented Here mindset. One step better is to not confuse that with refactoring or modernizing the code. If you really must switch from J2SE 1.4 to Java 8 to take advantage of 12 years of improvements and at the same time solve a great deal of technical debt, which will involve re-writing 90% of the codebase, go ahead. There is nothing wrong with reinventing the wheel here, because you have to. Just don't redevelop things for the sake of redevelopment.

Related to lesson #3: How can I convince management to deal with technical debt?

h.j.k.
  • 1,737
  • 1
  • 16
  • 20
  • 2
    The real anti-pattern here is leaving a job to write code from scratch. The new code will always end up just as foul. – Gusdor Mar 13 '15 at 10:58
7

Several ideas. Although I am not very sure how generally applicable they are.

First, in a lot of articles that reference this anti-pattern, the first advice is to resist the urge. One way to resist the urge is to understand the Dunning Kruger effect, and to spend time exploring whether the urge to refactor could have been influenced by the lack of familiarity of the original design and requirements of the existing architecture.

Second, along the same line of Dunning-Kruger effect, another way to resist the urge is to understand the "Shu-ha-ri" concept. That is, sufficient understanding and practice of the fundamentals is a prerequisite before one can contemplate exploration and innovation. When applied to the lava-flow anti-pattern, it means one should have a sufficient understanding of and maintenance experience on the existing system before being gradually allowed to make more dramatic changes to its architecture.

Third, an unreasonable yet sometimes effective way to resist the urge is to apply a healthy bit of "if it ain't broken, don't fix it." I say it is unreasonable because it is not based on reasoning, but instead on stubbornness. Yet it sometimes result in the correct outcome (a dramatic change not being carried out). The saying should not be taken literally; it should be seen as a tongue-in-cheek that reminds people of the importance of software stability.

Fourth, from the management perspective, lava-flow should be less likely to occur if there is more team continuity (that a team stays together for a longer period of time, without being overwhelmed by turnover rate, and for each project they work on, they will stick with it throughout a large part of its lifecycle.)

Some business analysis such as SWOT (strengths, weaknesses, opportunities, and threats) are useful in fostering an objective assessment of an architecture-change proposal.

Version control, change control and configuration management can be used to allow a team to safely explore alternative architectures while keeping the production system unaffected by the changes. If the exploration fails, it is acceptable to discard the failed attempts.

Finally, one must remember that innovation cannot happen in environments that do not permit exploration (and tolerate the risk of failures or wasted efforts).

h.j.k.
  • 1,737
  • 1
  • 16
  • 20
rwong
  • 16,695
  • 3
  • 33
  • 81
  • +1, also for citing the Dunning-Kruger effect. IMO one should apply the principle "If it ain't broke, don't fix it!" heavily. I think exploration of new technologies should be done in "new code". Old code can be changed if it does not work whereas changing old, working code is a mistake most of the times: we do not know how much work went into that code and how much implicit knowledge is hidden in it that makes it work properly. And here comes a new brilliant programmer that knows better, rewrites things and things stop working. I think a good programmer should be very conservative. – Giorgio Mar 13 '15 at 07:26
4

First of all, you have a human resources problem. If you want your experienced developers to stay, you need to give them a certain amount of greenfield work. Programmers can handle quite a bit of maintenance work if they also have a separate outlet for their creative urge to work on something new. Many programmers handle this on their own with hobby projects, but employers should be supportive. My company recently started doing hackathon contests once every 10 weeks to give people an outlet for innovation.

On a technical side, the problem isn't so much that the technology is changing. All code bases evolve, as third-party technologies are only supported for so long. The bigger problem here is that the changes are not getting completed before the next one starts. This is a sign of excessive coupling, poor cohesion, and poor testing practices in your code base. The solution therefore is to fix that first.

In other words, rather than slowly migrating to a new technology, slowly migrate to an architecture that will allow you to quickly migrate to a new technology. For an example, say you needed to change the operating system your product ran on. You can't just run part of two separate operating systems during the transition. What you can do is abstract away the OS-specific stuff little by little, then one day you'll be able to just flip the switch all at once.

Karl Bielefeldt
  • 146,727
  • 38
  • 279
  • 479