Back to TTCN-3 Refactoring Catalog

Extract Function

A group of statements can be moved into its own function.

Motivation

Typical smells for this refactoring are long functions or test cases and repeated code fragments. Extracting parts from a long function or test case increases the possibility for reuse or on the other hand may reduce code duplication. In either case it improves reusability, readability and reduces maintenance effort. Method names should be chosen with care as they should exactly represent the semantics of the method.

Usually, the concerned statements are extracted into a TTCN-3 function. Only in rare cases, however, the statements may be extracted into a test case. Hence, the refactoring name reflects only extraction into a function.

Mechanics

  • Create a new function and name it by what it does.
  • Copy the extracted code from the source location into the new target function.
  • Examine the extracted code for references to any variables, constants and timers that are local in scope of the source location, i.e. either locally defined temporary elements or elements passed as parameters to the source function. Port cannot be locally defined, but passed as parameters; in this case, they have also local scope.
    • Locally defined temporary elements which are only used in the extracted code are declared in the new target function again as local temporary elements. In a later step, their declaration can also be removed from the source location.
    • Temporary local-scope elements which are used before and after the extracted code must be passed to the target function as follows:
      • Timers and ports are always passed as reference, i.e. as inout.
      • Elements which are only read but not modified by the extracted code or read and modified by the extracted code but not read afterwards at the source location are passed as in parameter.
      • Elements that are modified but not read in the extracted code and read afterwards at the source location can be treated in two different ways: either they are passed as out parameters or they are returned by the function. The latter solution is only possible if only a single elements needs to be returned though. Other possibilities to improve the code for refactorings in these cases are the Split Temporary Variable and Replace Temp with Query refactorings. Mixing the return statement and out parameters is not recommended as it makes the function harder to understand and has to functional advantage.
      • Elements that are both read and modified in the extracted code and also read afterwards need to be passed as inout parameters or using in parameters and a return value if applicable.
  • Check whether the source method runs on a component. If so, find out whether any component specific variables are used in the extracted code. In this case, the extracted method needs to run on this component as well. Hence, the runs on specification from the source behavior needs to be added. Afterwards, 'Generalize Runs On' may be appropriate or the runs on specification may even be removed by applying 'Move Component Variable/Constant/Timer to Local Scope'.
  • Compile.
  • Replace the extracted code in the source behavior with a call to the new target function and provide any required parameters.
    • If any declarations of local temporary elements have been copied to the target function, remove their declaration from the source compound.
    • If the extracted code is duplicated at other locations, repeat the previous step for these alternate source locations. If these additional duplicated locations are not in the same module as the extracted target function, a corresponding import statement must be added or adjusted in the module of the additional duplicated code locations to import the target function.
  • Compile and validate.

Example

Sometimes, there needs to be a delay between two successive events in a TTCN-3. In the following listing, it is easy to detect the code duplication in the timer code of the f_sendMessages method. The Extract Function refactoring is used remove this duplication.

module ExtractFunctionExample {
  // ...

	type component ExampleComponent {
		timer t;
		port ExamplePort pt;
	}

  // ...

  function f_sendMessages(in float p_duration) 
    runs on ExampleComponent {
    
	  timer t;
	  t.start( p_duration );
	  t.timeout;
	
	  pt.send( a_MessageOne );

	  t.start( p_duration );
	  t.timeout;

	  pt.send( a_MessageTwo );	
  }
}

The result of the applied Extract Function refactoring to remove the code duplication is shown in the following listing. The new function f_wait contains the extracted code. According to the mechanic, the duration element is passed as in parameter as it is read, but not modified within the extracted code. As the timer accessed within the extracted code is a local element of the component, the f_wait function needs to run on ExampleComponent? as well.

module ExtractFunctionExample {
  // ...

	type component ExampleComponent {
		timer t;
		port ExamplePort pt;
	}

  // ...
  function f_wait(in float p_duration) 
  	runs on ExampleComponent{
	  t.start( p_duration );
	  t.timeout;
  }

  function f_sendMessages(in float p_duration) 
    runs on ExampleComponent {
	  timer t;
	
	  f_wait(p_duration);
	  pt.send( a_MessageOne );

	  f_wait(p_duration);
	  pt.send( a_MessageTwo );	
  }
}

Back to TTCN-3 Refactoring Catalog