Modernisation usually occurs incrementally, there would be very few success stories about legacy systems modernisation following a big bang approach.

Some important challenges when modernising incrementally are: determining the order, priorities and correctness of the new resulting system; where tests play a fundamental part.

The quantity and quality of tests seems to be inversely proportional to the uncertainty during a modernisation. The lesser the tests, the more we ignore.

According to Michael Feathers, legacy code is code without tests [1]. Because legacy is, as modern, a concept tight to time, I guess there would be some legacy code with tests.

In any case, let’s suppose you want to introduce tests or improve your harness. There’s always the question about where and how to do that. This article addresses specifically the where question, tests condition your modernisation, and vice-versa.

Many techniques can be used for determining where to add tests, you can count on deterministic, stochastic or just experience. Certainly there is no silver bullet and right technique, only a set of tools you can use depending on your case and the certainty that there is usually no money and time enough for adding all the tests you would like to add.

One key challenge for modernisation is to understand the system, so you can add tests. Some techniques mentioned by Robert C. Seacord et al [2] about code-structure representation are: Manual Code Reading, Artifact Extraction, Static Analysis, Dynamic Analysis, and Slicing.

The technique presented below belongs to the Dynamic Analysis approach set of tools, where “dynamic analysis observes a program executing in the operational environment or in a simulation of the operational environment” [2]

The idea is to understand how your app behaves through real logging information, understanding what is really important!. Profiling could be too expensive and not suitable for production environments.

You can add logging to the different layers of your application, for example: controllers, services and repositories. Specifically how long a function took to finish. Then you select one layer for starting, usually the uppermost layer (e.g. controller) and log elapsed times for a representative time window (e.g. 2 days).

Once your program finishes, you will have to extract:

  1. How many times a function was executed (hits)
  2. How long each function took to execute (elapsed time)

Now you can use a Priority Matrix [3] with hits vs elapsed time, to understand what is “important” (relevant at least). Keep in mind that you’ll have to position the centroid depending on the values you get for “x” and “y”. You could use averages for that, since all numbers are positive.

#software-architecture #testing #app-modernization #legacy-code #software-engineering

A Semi-Deterministic Approach for Directing Your Legacy Code Modernisation and Tests (1/2)
1.15 GEEK