11package cz .zcu .fav .kiv .antipatterndetectionapp .detecting .detectors ;
22
33import cz .zcu .fav .kiv .antipatterndetectionapp .detecting .DatabaseConnection ;
4- import cz .zcu .fav .kiv .antipatterndetectionapp .model .AntiPattern ;
5- import cz .zcu .fav .kiv .antipatterndetectionapp .model .Project ;
6- import cz .zcu .fav .kiv .antipatterndetectionapp .model .QueryResultItem ;
7- import cz .zcu .fav .kiv .antipatterndetectionapp .model .ResultDetail ;
4+ import cz .zcu .fav .kiv .antipatterndetectionapp .model .*;
85import org .slf4j .Logger ;
96import org .slf4j .LoggerFactory ;
107
11- import java .util .ArrayList ;
12- import java .util .List ;
13- import java .util .Map ;
8+ import java .util .*;
149
1510public class NinetyNinetyRuleDetectorImpl implements AntiPatternDetector {
1611
@@ -19,18 +14,31 @@ public class NinetyNinetyRuleDetectorImpl implements AntiPatternDetector {
1914 private final AntiPattern antiPattern = new AntiPattern (7L ,
2015 "Ninety Ninety Rule" ,
2116 "NinetyNinetyRule" ,
22- "TODO" );
17+ "The first 90 percent of the code represents the first 90 percent of development time. The " +
18+ "remaining 10 percent of the code represents another 90 percent of development time. " +
19+ "Then decide on a long delay of the project compared to the original estimate. " +
20+ "The functionality is almost done, some number is already closed and is only waiting " +
21+ "for one activity to close, but it has been open for a long time." ,
22+ new HashMap <>() {{
23+ put ("maxDivisionRange" , new Configuration <Double >("maxDivisionRange" ,
24+ "Maximum ration value" ,
25+ "Maximum ratio value of spent and estimated time" , 1.2 ));
26+ put ("maxBadDivisionLimit" , new Configuration <Integer >("maxBadDivisionLimit" ,
27+ "Maximum iterations thresholds" ,
28+ "Maximum number of consecutive iterations where the thresholds were exceeded" , 2 ));
29+ }});
2330
2431 private final String sqlFileName = "ninety_ninety_rule.sql" ;
2532 // sql queries loaded from sql file
2633 private List <String > sqlQueries ;
2734
28- /**
29- * SETTINGS
30- */
31- private static final double MAX_DIVISION_RANGE = 1.2 ;
32- private static final double MIN_DIVISION_RANGE = 0.8 ;
33- private static final int MAX_BAD_ITERATION_LIMIT = 3 ;
35+ private double getMaxDivisionRange () {
36+ return (Double ) antiPattern .getConfigurations ().get ("maxDivisionRange" ).getValue ();
37+ }
38+
39+ private int getMaxBadDivisionLimit () {
40+ return (int ) antiPattern .getConfigurations ().get ("maxBadDivisionLimit" ).getValue ();
41+ }
3442
3543 @ Override
3644 public AntiPattern getAntiPatternModel () {
@@ -51,9 +59,9 @@ public void setSqlQueries(List<String> queries) {
5159 * Postup detekce:
5260 * 1) pro každou iteraci udělat součet stráveného a odhadovaného času přes všechny aktivity
5361 * 2) udělat podíl strávený čas / odhadovaný čas
54- * 3) pokud všechny výsledky podílů budou v rozsahu 0.8 - 1.2 => vše ok
62+ * 3) pokud všechny výsledky podílů budou menší než 1.2 => vše ok
5563 * 4) pokud předchozí bod nezabere, tak iterovat přes všechny podíly
56- * 5) pokud budou nalezeny tři iterace po sobě, které se stále zhoršují stejným směrem => detekce
64+ * 5) pokud budou nalezeny tři iterace po sobě, kde se stále zhoršují odhady => detekováno
5765 *
5866 * @param project analyzovaný project
5967 * @param databaseConnection databázové připojení
@@ -76,7 +84,7 @@ public QueryResultItem analyze(Project project, DatabaseConnection databaseConne
7684 }
7785 divisionsResults .add (resultDivision );
7886 // if is one division is out of range set boolean to false
79- if (resultDivision > MAX_DIVISION_RANGE || resultDivision < MIN_DIVISION_RANGE ) {
87+ if (resultDivision > getMaxDivisionRange () ) {
8088 isAllInRange = false ;
8189 }
8290 }
@@ -89,29 +97,19 @@ public QueryResultItem analyze(Project project, DatabaseConnection databaseConne
8997 }
9098
9199 int counterOverEstimated = 0 ;
92- int counterUnderEstimated = 0 ;
93100 for (Double divisionResult : divisionsResults ) {
94- if (divisionResult > MAX_DIVISION_RANGE ) {
101+ if (divisionResult > getMaxDivisionRange () ) {
95102 counterOverEstimated ++;
96- counterUnderEstimated = 0 ;
97- }
98-
99- if (divisionResult < MIN_DIVISION_RANGE ) {
100- counterUnderEstimated ++;
103+ } else {
101104 counterOverEstimated = 0 ;
102105 }
103106
104- if (counterOverEstimated >= MAX_BAD_ITERATION_LIMIT ) {
107+ if (counterOverEstimated > getMaxBadDivisionLimit () ) {
105108 resultDetails .add (new ResultDetail ("Conclusion" ,
106- "Found bad significant trend in estimated time - over estimated. " ));
107- return new QueryResultItem (this .antiPattern , false , resultDetails );
109+ getMaxBadDivisionLimit () + " or more consecutive iterations has a bad trend in estimates " ));
110+ return new QueryResultItem (this .antiPattern , true , resultDetails );
108111 }
109112
110- if (counterUnderEstimated >= MAX_BAD_ITERATION_LIMIT ) {
111- resultDetails .add (new ResultDetail ("Conclusion" ,
112- "Found bad significant trend in estimated time - under estimated." ));
113- return new QueryResultItem (this .antiPattern , false , resultDetails );
114- }
115113 }
116114
117115 resultDetails .add (new ResultDetail ("Conclusion" ,
0 commit comments