When trying to separate a Legacy System with seams, it is important to know what type of common seams are available. The type of seam a system will have will depend on the language being used.
Preprocessing Seams
This is more common in older programming language; a preprocessing seam will be a seam that is created before the processor runs. Programming languages have a compiler that reads program text and produces object code or byte code instructions. In languages like C++, we can specify arguments for the preprocessor that is used to help the compiler.
Using definitions, we provide to the preprocessor, we can specify variables that we want replaced at runtime. In the case of a local runtime, we can provide a substitute for a challenging seam, such as a network connection. With a local replacement of a network connection in place, we can verify that the connection is being called with the correct parameters in place. We can do this by using the #include directive for the preprocessor, which provides us with a seam where we can replace text before it is compiled.
Link Seams
The compilers job is to present a representation of the code, which will contain calls to other code to support the functionality of a particular class. These calls are represented by Linkers, which resolve each call to give you a complete program at runtime. In the Java system I work in, the linking will be handled by the Compiler behind the scenes – rather than a true Linker. The ‘linker’ will check all import statements, compile the code, and make sure all calls resolve. It is here where we can exploit the linker to swap pieces of the code.
Take a look at the example below, a representation of an automotive ECU:
package auto.ecu.main;
import java.util.Date;
import auto.ecu.user.display.GaugeCluster;
import auto.ecu.utilities.ECUParser;
public class AutomotiveECU {
private Date ecuTime = new Date();
private GaugeCluster clusterDisplay;
public void initializeECU() {
String clusterTime;
clusterDisplay = new GaugeCluster(ecuTime);
ECUParser ecuParser;
clusterTime = monitorGauges(ecuParser);
}
public String monitorGauges(ECUParser ecuParser) {
String gaugeClusterTime = ecuParser.parseDateTime(clusterDisplay);
return gaugeClusterTime;
}
}
We have the Automotive ECU which imports and uses other components, such as the ECU Parser. If we needed to test monitoring the gauges, but the clusterDisplay object was really difficult to build, we could substitute the class path of GaugeClusterDisplay at compile time to a simple ‘dummy’ version of the object. This type of work has been simplified by mocking libraries, but it is key to understand how to identify a seam in this way.
Object Seams
Object Seams are a common type of seam in Object Oriented languages, and are also very useful. Most OO languages are flexible, when you example a call in an object oriented program, it doesn’t define which method will actually be executed. Let’s look at the monitorGauges method from above.
public String monitorGauges(ECUParser ecuParser) {
String gaugeClusterTime = ecuParser.parseDateTime(clusterDisplay);
return gaugeClusterTime;
}
The processor knows that we are making a call to a method named parseDateTime, passing it an instance of GaugeCluster called clusterDisplay. With Java, we are able to have more than one method defined this way. If we have a large set of classes with multiple clusters, we can implement an abstract class called ‘Parser’ – where ECUParser and a new class ConsoleParser both inherit their behaviors from. Being able to change the behavior without changing the code in the monitorGauges method makes parseDateTime an object seam.
public String monitorGauges(Parser ecuParser) {
String gaugeClusterTime = ecuParser.parseDateTime(clusterDisplay);
return gaugeClusterTime;
}
Keep in mind that if we defined ecuParser in the in the method, this would not be a seam. It is currently defined outside of the method and can be changed without making changes to the object.
You should be mindful of what seams you use to get your code under test. Object seams are only available in object oriented languages; and preprocessing/link seams are going to be more useful in older languages. The tests that depend on the preprocessing and link seams are challenging to maintain, with things such as varying build scripts between environments.