Scales

Scales define grades and boundaries for measures, in order to translate them into more understandable information. There are two type of scales in Squore, static and dynamic scales.

Static scales

Static scales are define using a Scale element combined with several ScaleLevel sub-elements in order to define the ranges in the scale.

<Scale scaleId="SCALE_EC">
	<ScaleLevel levelId="UNKNOWN" bounds="];0[" rank="-1" />
	<ScaleLevel levelId="LEVELA" bounds="[0;0]" rank="0" />
	<ScaleLevel levelId="LEVELB" bounds="]0;1]" rank="1" />
	<ScaleLevel levelId="LEVELC" bounds="]1;2]" rank="2" />
	<ScaleLevel levelId="LEVELD" bounds="]2;3]" rank="3" />
	<ScaleLevel levelId="LEVELE" bounds="]3;4]" rank="4" />
	<ScaleLevel levelId="LEVELF" bounds="]4;5]" rank="5" />
	<ScaleLevel levelId="LEVELG" bounds="]5;]" rank="6" />
</Scale>

In this example, the scale SCALE_EC associates different levels to a measured value:

  • If the measured value is less than 0, the levelId is UNKNOWN with ranking -1.

  • If the measured value is exactly 0, the levelId is A with ranking 0.

  • If the measured value is between 0 (excluded) and 1 (included), the levelId is B with ranking 1.

  • If the measured value is between 1 (excluded) and 2 (included), the levelId is C with ranking 2.

  • If the measured value is between 2 (excluded) and 3 (included), the levelId is D with ranking 3.

  • If the measured value is between 3 (excluded) and 4 (included), the levelId is E with ranking 4.

  • If the measured value is between 4 (excluded) and 5 (included), the levelId is F with ranking 5.

  • If the measured value is more than 5 (excluded), the levelId is G with ranking 6.

The use of unions in scale bounds has been deprecated since Squore 16.0. You now need to use two distinct scale levels, as shown in the following example:

Old syntax:

<Scale scaleId="SCALE_EC2">
	<ScaleLevel levelId="LEVEL_IN" bounds=" ]0;10[|]10;100[" rank="0"/>
	<ScaleLevel levelId="LEVEL_OUT" bounds="[10;10]" rank="1"/>
</Scale>

Current syntax:

<Scale scaleId="SCALE_EC2">
	<ScaleLevel levelId="LEVEL_IN_LOW" bounds=" ]0;10[" rank="0"/>
	<ScaleLevel levelId="LEVEL_OUT" bounds="[10;10]" rank="1"/>
	<ScaleLevel levelId="LEVEL_IN_HIGH" bounds=" ]10;100[" rank="0"/>
</Scale>

Scales can be overridden for a specific artefact type, as shown below:

<Indicator indicatorId="VG" measureId="VG" scaleId="VG" targetArtefactTypes="CODE" />
<Scale scaleId="VG">
	<ScaleLevel levelId="UNKNOWN"	bounds="];0[" rank="-1" />
	<ScaleLevel levelId="GREEN"	bounds="[0;6]" rank="0" />
	<ScaleLevel levelId="YELLOW"	bounds="]6;10]" rank="1" />
	<ScaleLevel levelId="RED" bounds="]10;[" rank="2" />
</Scale>

<Scale scaleId="VG" targetArtefactTypes="COBOL_PROGRAM">
	<ScaleLevel levelId="UNKNOWN"	bounds="];0[" rank="-1" />
	<ScaleLevel levelId="GREEN"	bounds="[0;10]" rank="0" />
	<ScaleLevel levelId="YELLOW"	bounds="]10;20]" rank="1" />
	<ScaleLevel levelId="RED" bounds="]20;[" rank="2" />
</Scale>

The scale VG applies to all artefacts of type CODE, however, for artefacts of type COBOL_PROGRAM, the scale levels have different bounds than for other types (as specified via the targetArtefactTypes attribute).

You can use scale macros in order to avoid duplicating a scale and use parameters ({0}, {1}…​) to define the scale level thresholds:

<ScaleMacro id="RGB">
	<ScaleLevel levelId="UNKNOWN"	bounds="];0[" rank="-1" />
	<ScaleLevel levelId="GREEN"	bounds="[0;{0}]" rank="0" />
	<ScaleLevel levelId="YELLOW"	bounds="]{0};{1}]" rank="1" />
	<ScaleLevel levelId="RED" bounds="]{1};[" rank="2" />
</ScaleMacro>

Scales defined by a macro and its parameters are then specified as shown below:

<Scale scaleId="VG" macro="RGB" vars="6;10" />
<Scale scaleId="VG_REVERSED" macro="RGB" vars="10;6" />

The UNKNOWN level receives special treatment when it comes to showing a trend:

  • When the rank goes from the UNKNOWN level to any other level, the trend is shown as: CFG tree new

  • When the rank goes from any level to UNKNOWN, the trend is shown as: CFG tree down

Supported attributes for Scale element

  • scaleId (mandatory) the unique identifier of the scale

  • targetArtefactTypes (optional) the specific artefacts that this scale applies to. If this attribute is omitted, then the value of targetArtefactTypes specified for the indicator using this scale is used.

  • macro (optional) specifies the id of the ScaleMacro used to define this scale

  • vars (optional) is a semicolon-separated list of parameters to pass to the ScaleMacro to define this scale

  • isDynamic (optional, default: false) whether the scale levels are dynamic or not. Read more about the concept of dynamic scales in Dynamic scales.

Supported attributes for ScaleLevel element

Scale levels are defined using one or more ScaleLevel sub-elements, with the following attributes:

  • levelId (mandatory) the unique identifier of the scale level.

  • bounds (mandatory) the value limits for this scale level. Infinite bounds can be specified by omitting the number, e.g.: [0;[ or [0;] for any null or positive number.

  • rank (mandatory) the weight of the scale which is used when aggregating values.

Supported attributes for RankFormat element

Additional RankFormat sub-element can be defined in order to specify the display format of ranks. Accepted attributes are the following:

  • dataBounds (optional, default: none) allows specifying which range of values should be considered valid for this measure (currently this applies to the Indicator Tree and the Measures tab only).

  • invalidValue (optional, default: -) is the text that should be displayed when an invalid value is set for the measure (currently this applies to the Indicator Tree and the Measures tab only).

  • noValue (optional, default: ?) is the text displayed when no value exists for this metric in the database (currently this applies to the Indicator Tree and the Measures tab only).

  • format (optional, default: NUMBER) is the format used to display the value of the measure in the UI. Accepted values are:

    • NUMBER which accepts the following additional parameters when defined:

      • decimals (optional, default: 0) is the number of decimals places to be used for displaying values.

      • roundingMode (optional, default: HALF_EVEN) defines the behaviour used for rounding the numerical values displayed. The supported values are:

        • CEILING to round towards positive infinity.

        • DOWN to round towards zero.

        • FLOOR to round towards negative infinity.

        • HALF_DOWN to round towards "nearest neighbour" unless both neighbours are equidistant, in which case round down.

        • HALF_EVEN to round towards the "nearest neighbour" unless both neighbours are equidistant, in which case, round towards the even neighbour.

        • HALF_UP to round towards "nearest neighbour" unless both neighbours are equidistant, in which case round up.

        • UP to round away from zero.

        For more examples of rounding mode, consult http://docs.oracle.com/javase/8/docs/api/java/math/RoundingMode.html

    • PERCENT which accepts the following additional parameters when defined:

      • decimals (optional, default: 0) is the number of decimals places to be used for displaying values.

      • roundingMode (optional, default: HALF_EVEN) defines the behaviour used for rounding the numerical values displayed. The supported values are:

        • CEILING to round towards positive infinity.

        • DOWN to round towards zero.

        • FLOOR to round towards negative infinity.

        • HALF_DOWN to round towards "nearest neighbour" unless both neighbours are equidistant, in which case round down.

        • HALF_EVEN to round towards the "nearest neighbour" unless both neighbours are equidistant, in which case, round towards the even neighbour.

        • HALF_UP to round towards "nearest neighbour" unless both neighbours are equidistant, in which case round up.

        • UP to round away from zero.

        For more examples of rounding mode, consult http://docs.oracle.com/javase/8/docs/api/java/math/RoundingMode.html

    • ENUM which requires the following additional parameter when defined:

      • enumId (mandatory) to define the ID of the enumeration (Enumerations).

    • BOOLEAN

    • MAN_DAYS

    • MAN_HOURS

    • MAN_MINUTES

    • MAN_SECONDS

    • MAN_MILLISECONDS

    • DAYS

    • HOURS

    • MINUTES

    • SECONDS

    • MILLISECONDS

    • INTEGER which accepts the following additional parameter when defined:

      • roundingMode (optional, default: HALF_EVEN) defines the behaviour used for rounding the numerical values displayed. The supported values are:

        • CEILING to round towards positive infinity.

        • DOWN to round towards zero.

        • FLOOR to round towards negative infinity.

        • HALF_DOWN to round towards "nearest neighbour" unless both neighbours are equidistant, in which case round down.

        • HALF_EVEN to round towards the "nearest neighbour" unless both neighbours are equidistant, in which case, round towards the even neighbour.

        • HALF_UP to round towards "nearest neighbour" unless both neighbours are equidistant, in which case round up.

        • UP to round away from zero.

        For more examples of rounding mode, consult http://docs.oracle.com/javase/8/docs/api/java/math/RoundingMode.html

    • DATE | TIME | DATETIME which accepts the following additional parameters when defined:

      • dateStyle (optional, default: DEFAULT) : the date formatting style, used when the displayType is one of DATE or DATETIME.

        • SHORT is completely numeric, such as 12.13.52 or 3:30pm.

        • MEDIUM is longer, such as Jan 12, 1952.

        • DEFAULT is MEDIUM.

        • LONG is longer, such as January 12, 1952 or 3:30:32pm.

        • FULL is pretty completely specified, such as Tuesday, April 12, 1952 AD or 3:30:42pm PST.

      • timeStyle (optional, default: DEFAULT): the time formatting style, used when the displayType is one of DATETIME or TIME. See above for available styles.

The levelId attributes are then mapped to their language-specific attributes in a properties file. For the previous example, the file PerformanceLevels_en.properties gives the following mapping:

LOP.LEVELA.MNEMO=A
LOP.LEVELA.NAME=Level A
LOP.LEVELA.COLOR=0,81,0
LOP.LEVELA.IMAGE=../Shared/Images/images/perfA.png
LOP.LEVELA.ICON=../Shared/Images/icons/perfA.png

Dynamic scales

Dynamic scales are scales whose levels use measures instead of absolute bounds. They are useful when one metric has a different meaning according to the context in which it is read. In software development for example, you may accept a certain amount of specification changes at one stage of the process, but completely want to prohibit it at another stage. This section takes you through an example that can be implemented easily in your model with the use of dynamic scales.

What we want to guarantee with our dynamic scale, is that during three different phases of development, our requirements stability indicator is evaluated differently, as represented below:

CFG dynamic scale explained
Figure 1. Requirement Stability by Development Phase

The following is an example of a dynamic scale definition for a KPI that evaluates the stability of requirements as excellent, fine, worrying, critical or unknown:

<Scale scaleId="DYN_SCALE_REQ_STABILITY" isDynamic="true">
	<ScaleLevel levelId="DYN_EXCELLENT" bounds="[APP(EXCELLENT_THRESHOLD);[" rank="0" />
	<ScaleLevel levelId="DYN_FINE" bounds="[APP(FINE_THRESHOLD);APP(EXCELLENT_THRESHOLD)[" rank="1" />
	<ScaleLevel levelId="DYN_WORRYING" bounds="[APP(WORRYING_THRESHOLD);APP(FINE_THRESHOLD)[" rank="2" />
	<ScaleLevel levelId="DYN_CRITICAL" bounds="[APP(CRITICAL_THRESHOLD);APP(WORRYING_THRESHOLD)[" rank="3" />
	<ScaleLevel levelId="DYN_UNKNOWN" bounds="];APP(CRITICAL_THRESHOLD)[" rank="4" />
</Scale>

Only measureId or APP(measureId) are allowed in the bounds attribute.

Compared with the examples of scales shown in Scales, note the use of the isDynamic attribute and how the bounds are expressed with measures instead of actual values.

The threshold measures can vary for each analysis and/or for each artefact type, and the scale may therefore be different as time goes by. There are two ways they could be set:

  1. By using attributes at application levels so that users define the values of the thresholds manually.

  2. By computing the thresholds during the analysis with IF(), CASE() or other available functions described in Functions

Here is an example setting the thresholds according to a PHASE attribute set by the user before running an analysis (more information about attributes is available in Forms:

<!-- Attribute Definition in Wizard -->
<tag type="multipleChoice" name="Development Phase: " measureId="PHASE" defaultValue="SPECIFICATION" displayType="radioButton" targetArtefactTypes="APPLICATION">
	<value key="SPECIFICATION" value="1" />
	<value key="PROTOTYPING" value="2" />
	<value key="IMPLEMENTATION" value="3" />
</tag>

<!-- Metrics Definition in Analysis Model -->
<Measure measureId="PHASE" targetArtefactTypes="APPLICATION" defaultValue="0" />
<Constant id="PHASE_SPECIFICATION" value="1" />
<Constant id="PHASE_PROTOTYPING" value="2" />
<Constant id="PHASE_IMPLEMENTATION" value="3" />

<!-- Thresholds Computation in Analysis Model -->
<Measure measureId="EXCELLENT_THRESHOLD">
	<Computation targetArtefactTypes="APPLICATION"
		result="CASE(PHASE,
		C.PHASE_SPECIFICATION:60,
		C.PHASE_PROTOTYPING:95,
		C.PHASE_IMPLEMENTATION:100,
		DEFAULT:-1)"/>
</Measure>
<Measure measureId="FINE_THRESHOLD">
	<Computation targetArtefactTypes="APPLICATION"
		result="CASE(PHASE,
		C.PHASE_SPECIFICATION:30,
		C.PHASE_PROTOTYPING:80,
		C.PHASE_IMPLEMENTATION:99,
		DEFAULT:-1)"/>
</Measure>
<Measure measureId="WORRYING_THRESHOLD">
	<Computation targetArtefactTypes="APPLICATION"
		result="CASE(PHASE,
		C.PHASE_SPECIFICATION:10,
		C.PHASE_PROTOTYPING:40,
		C.PHASE_IMPLEMENTATION:95,
		DEFAULT:-1)"/>
</Measure>
<Measure measureId="CRITICAL_THRESHOLD">
	<Computation targetArtefactTypes="APPLICATION"
		result="CASE(PHASE,
		C.PHASE_SPECIFICATION:0,
		C.PHASE_PROTOTYPING:20,
		C.PHASE_IMPLEMENTATION:90,
		DEFAULT:-1)"/>
</Measure>

The final REQUIREMENTS_STABILITY indicator is associated with a static scale that uses the same ranks as the dynamic one, and its value is assigned by retrieving the desired rank from the dynamic scale using the FIND_RANK() function:

<!-- Static scale to base the KPI on -->
<Scale scaleId="SCALE_REQ_STABILITY">
	<ScaleLevel levelId="EXCELLENT" bounds="[0;0]" rank="0" />
	<ScaleLevel levelId="FINE" bounds="[1;1]" rank="1" />
	<ScaleLevel levelId="WORRYING" bounds="[2;2]" rank="2" />
	<ScaleLevel levelId="CRITICAL" bounds="[3;3]" rank="3" />
	<ScaleLevel levelId="UNKNOWN" bounds="[4;4]" rank="4" />
</Scale>

<!-- Indicator definition -->
<Indicator indicatorId="REQUIREMENTS_STABILITY" measureId="REQ_STABILITY_RANK" targetArtefactTypes="APPLICATION;FOLDER;FILE" scaleId="SCALE_REQ_STABILITY" />

<!-- The base measure that holds the actual raw value of Requirement Stability -->
<Measure measureId="REQUIREMENTS_STABILITY_METRIC" targetArtefactTypes="APPLICATION;FOLDER;FILE" defaultValue="0" />

<!-- A temporary measure to compute the rank of the metric on the dynamic scale -->
<Measure measureId="REQ_STABILITY_RANK">
	<Computation stored="false" targetArtefactTypes="APPLICATION;FOLDER;FILE" result="FIND_RANK(DYN_SCALE_REQ_STABILITY, REQUIREMENTS_STABILITY_METRIC)" />
</Measure>

For more information about the FIND_RANK() function, refer to Functions.

When using dynamic scales, the scale and measure computed for an indicator may not make sense for the end user. In this case, you may want to change what the user sees via the use of the displayedScale and displayedValue attributes in your indicator definition. For more information about this syntax, consult Indicators.