Irrationality at the service of rationality in decision-making

The shared decision, or group decision, is one of the fundamental stones of modern western civilization, democracy itself is based on this concept. But how far do groups make the best decision? How much of the expected goal – as a group decision – is obtained from a project approval committee or team meeting to validate the schedule?

Arthur's Round Table

In Arthur’s reign, decisions were shared by peers

Legend has it that King Arthur had a round table for meetings, the Round Table, where all were equal and therefore were equally involved in the decisions taken there. In the company where we work, we like the idea of participating in relevant events, including decision making, this is the natural desire for democracy, even if a company is not a democratic institution.

Group decision-making in companies is an administrative theory that aims at several advantages such as increased workplace satisfaction, motivation as a result of participation, and which ultimately results in a positive organizational atmosphere as well as increased productivity. The popular concept that “many heads think better than one” can materialize in decisions with levels of quality superior to those individual decisions. We just do not know what to do with the perception that team decision-making can be unproductive and frustrating for wasting time – and money.

Max Gehringer, business administrator and writer, author of the book Classics of the Corporate World, says in his article The Seven Rules of the “Never” Manual for Projects: “Never try to convince if you can command.”

The Milgram's Experience

Milgram’s Experiment: E=Experimenter, S=Subject, A=Actor

There is a macabre aspect of group decision-making and it is inherent to the main actor on stage: the human being. In 1964, an experiment led by psychologist Stanley Milgram placed a group of volunteers in a room on the other side of which, separated by a thin wall, one of the randomly selected volunteers was positioned sitting and tied to a chair. With every question the researcher made to the man obtaining a wrong answer, the group would press a button that would inflict an electric shock on the volunteer. At first the shocks were light and fast, but over time they became strong and intense – and so did the shouts of the volunteer. Finally, after a long shock, the man was silent, and a bad atmosphere took over the place. Of course this was an experiment, and the man, a real actor, was never inflicted any shock. What was important in the research was the finding that the group lost sense of responsibility – in this case, for the punishment – since the decision was made by the group rather than by the individual. A control test showed that being an individual decision, the participants did not inflict this level of electric shock to the poor man.

Free Vermeulen

Freek Vermeulen, author of Business Exposed

The London Business School professor and author of the book Business Exposed, Freek Vermeulen, talks about people’s inclination to imitate others’ behavior. In fact, this is perhaps one of our first impulses, and the one responsible for our learning to speak, to walk and … to make decisions. It is easy to imagine a decision-making meeting where the first one who ventures into giving an opinion is followed by the others, while another group simply omits. Moreover, the omission is explained by Freek as an inhibition and not as a sign of agreement; “those who are silent, consent”. The fact is that nobody likes to be the minority, either when cheering for a football team or during a major decision in the company. “The consequence of this is that, in a meeting, it may happen that everyone is diverging, but no one speaks up because they are reluctant,” says the professor.

So what do we do with the shared decision, now that we have demonized it? Sometimes it is necessary to tear down walls to build foundations. So let’s learn how to extract from shared decision your best and in the best possible way, in order to ensure that in a project approval committee, or in the team meeting for validation – and of course approval – we achieve superior commitment and maturity.

Norman Maier, an American experimental psychologist, advocates for the method of group decision-making in the practice of effective command. In his studies, Maier takes into account two dimensions. The first is the internal social weight, and the second is the weight in organizational efficiency. By creating a matrix of these two dimensions, we can fit each decision into a quartile. Maier concluded that it is possible to significantly reduce the bias of shared decision by electing a “professional integrator.”

maier_matrix

Maier’s imaginary matrix for decision model

This figure is responsible for keeping a high level of discussion, valuing the sphere of information and skilfully leading to the choice of a solution. The professional integrator takes place in critical decisions, where the room for maneuver is reduced, and the group can not decide beyond certain limits. There is one more aspect in this form of decision making, to get a decision that is not a decision. The integrator manipulates the group to a more or less predetermined decision, giving word to the right person, suspending the meeting, or declaring the meeting finished at the appropriate time. Skill is essential to accomplish all of this without the members having a perception of manipulation while getting the best of the process of resistance to change, the “acceptance of the consequences of the decision.”

Manhattan Connection guys

Manhattan Connection program commentators. Lucas Mendes (center) is an example of a Maier’s professional integrator

The model suggested by Maier reminds me a lot of the Manhattan Connection program (despite its name, a brazilian show), shown on the Globo News paid channel. On air for 19 years, political, economic and cultural commentators debate on several highlights of the week. A table of discussion sometimes chaotic, but that is expertly coordinated by journalist Lucas Mendes, who plays the role of professional animator, bringing the subject and directing the discussion until reaching (almost always) the result. Result which you can imagine beforehand to be the one expected.

Planning for shared decision-making, and carrying out the process in a less orthodox way, can make it easy to implement a good decision-making system. The effort expended on the activity is rewarded with motivation, participation and commitment of those involved in the practical implementation of the decision.


Coding SVN hook in Java

In the How IT of today we create a SVN pre-commit’ hook coded in Java language 🙂

captain.hook

Why we need this

From small teams to really big teams counting more than 100 heads, the source control is almost mandatory. Apache Subversion (SVN) is one of most popular solution for software versioning and release control. Despite that as standard installation the application has no way to validate anything committed by users, SVN is very flexible to accept externals applications which are referred as hooks. Each hook will be executed in a specific step of the process; start-commit, pre-commit, pre-lock, pre-unlock, post-commit, etc.

SVN hooks can be used for almost everything, but commonly they do notification, validation, or replication over each operation. So, this could be the source of power over all bad artefacts submitted by users and prevent the lack of documentation in your application source code.

What we need

Development

  • JDK 1.7+
  • Log4J 1.2.16
  • SVNKit 1.8.12
  • Maven 3.0.5+

Execution – server

  • VisualSVN Server 3.7.1 (including SVN 1.9.7)
  • Microsoft Windows (just because of shell scripts)

Execution – client

  • TortoiseSVN 1.9.7+ (or your favourite SVN clients flavour)

How to

Let’s create a hypothetical scenario where we need to validate the name of files submitted by the team. Also, we need to be sure that no unacceptable word is going to be used in our artefacts contents. In this case, we want to stop the commit before the bad file turns part of the repository.

To achieve this goal we must create two hooks (could be only one, but for educational purposes will be two), which will be executed in pre-commit step. therefore, in case of break of rules, the commit will not be concluded.

A pattern to make it easy

First things first, we need to prepare the following dependencies in pom.xml:

<!-- Log4J -->
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.16</version>
</dependency>
<!-- SVN -->
<dependency>
  <groupId>org.tmatesoft.svnkit</groupId>
  <artifactId>svnkit</artifactId>
  <version>1.8.12</version>
</dependency>

The first validation will check if the file name contains only letters and number. It’s not a big challenge, right? Indeed! To do this task we coded the file TickingClockHook.java:

@Override
public void validate(String[] args) throws PreCommitException
{
	//Isolate the file name
	String fileName = args[4];
	log.debug("File name: " + fileName);
	if (fileName.contains("/"))
	{
		fileName = fileName.substring((fileName.lastIndexOf("/") + 1), fileName.length());
	}
	fileName = fileName.substring(0, fileName.indexOf("."));
	
	//Pattern to accept only letters and numbers
	Pattern pattern = Pattern.compile("^[a-zA-Z0-9]+$");
	
	if (!pattern.matcher(fileName).matches())
	{
		throw new PreCommitException("The file name must use only letters and numbers; " + fileName + " is not valid.");
	}
}

That was easy! As you can see, nothing in this method is exotic or hard to understand. Please, take a look at:

  • Line 51: we are reading the file name in method’s argument
  • Lines 53-57: isolate the file name from path and extension
  • Line 60: the regular expression to accept only letters and numbers is created
  • Line 62: verify if the file name matches to the pattern
  • Line 64: when the file name contains any non-alphabetic characters or numerics, the validation fails

Ok, but… is it works? Sure! See this output when trying to commit the file test-123.java:

Error: Commit failed (details follow):
Error: Commit blocked by pre-commit hook (exit code 1) with output:
Error: ==============================================================
Error:
Error: Your commit is blocked since the file name is not accepted.
Error: File: trunk/test-123.java
Error: Reason: The file name must use only letters and numbers; test-123 is not
Error: valid.
Error: You should fix it to try again.
Error:
Error: ==============================================================
Error: If you want to break the lock, use the 'Check For Modifications' dialog or the repository browser.

What about the validation of contents? Let’s see what is coded in BadLanguageHook.java:

@Override
public void validate(String[] args) throws PreCommitException
{
	String contents = loadFileContents(args[1], getUsername(), getPassword(), args[2], args[4]).toUpperCase();
	
	for (String word : bannedWords)
	{
		log.debug("Looking for: " + word);
		if (contents.contains((word.toUpperCase())))
		{
			throw new PreCommitException("Is not acceptable the use of " + word + " in contents of files.");
		}
	}
}

Less lines and nothing difficult:

  • Line 54: the file contents are read
  • Line 56: check for each banned word on the list
  • Line 59: look in contents for the forbidden word
  • Line 61: if the word is there, the validation fails

When we try to commit a dirty file:

Error: Commit failed (details follow):
Error: Commit blocked by pre-commit hook (exit code 1) with output:
Error: ==============================================================
Error:
Error: Your commit is blocked since something in file contents is not
Error: allowed.
Error: File: trunk/JollyRoger.java
Error: Reason: Is not acceptable the use of peter pan in contents of files.
Error: You should fix it to try again.
Error:
Error: ==============================================================
Error: If you want to break the lock, use the 'Check For Modifications' dialog or the repository browser.

After to behold the magic, we can check inside of the top hat.

I created a set of three classes as a pattern to make easy the creation of any hook of pre-commit to SVN.

The complete source code, compiling and shinning is available in my GitHub.

Let’s see the first and “core” of this pattern, the PreCommitInterdiction.java class:

public final static void main(String args[])
{
  //Checking for valid entries
  if (!hasValidArguments(args))
  {
    defineAsInternalError("This execution is invalid. Please, check for pre-commit script and useful messages in your log file " + LOG4J_LOG_FILE);
  }
  else
  {
    //Instantiate the hook
    PreCommitHook hook = createHook(args[0]);
    
    //Executes the validation using the hook
    try
    {
      if (hook != null)
      {
        hook.validate(args);
        printSuccess();
      }
    }
    catch (PreCommitException ex)
    {
      log.error("Could not validate because a pre-commit exception happened: " + ex.getMessage(), ex);
      printFail(ex.getMessage());
    }
    catch (Exception ex)
    {
      log.error("Could not validate because a general exception happened: " + ex.getMessage(), ex);
      defineAsInternalError(ex.getMessage());
    }
  }
  log.debug("...end!");
}

The method main is responsible to validate its arguments and call for the hook:

  • Line 146: check if calling arguments are valid
  • Line 153: instantiate the implementation of pre-commit hook
  • Line 160: execute the validation implemented by the hook
  • Line 167: when the validation fails, a message is printed explaining it
  • Line 172: if an unexpected error occurs, a message explaining it is printed

As you may notice, the highlighted line 160 is the point of interest in this map. The program calls the method validate of hook’s class, it comes from the interface PreCommitHook.java:

public interface PreCommitHook
{
  /**
   * Performs the validation of commit.
   * 
   * @param args Array of parameters to execute the hook.
   * @throws PreCommitException Happens when any or all implemented rules are broken.
   */
  public void validate(String[] args) throws PreCommitException;
}

This interface has to be implemented by all pre-commit hook classes and has only one method to override, it is validate.

The third class is our specific implementation of Exception, the PreCommitException.java:

public class PreCommitException extends Exception
{
	/**
	 * New friendly pre-commit exception.
	 * 
	 * @param message Explanation of the exception
	 */
  public PreCommitException(String message)
  {
    super(message);
  }
}

There is nothing special in this exception besides it is being used to thrown specific issues in the validation process.

Back to hook which is responsible to validate the file contents, in line 54 of file BadLanguageHook.java, what is the method loadFileContents? It comes from its superclass. All pre-commit hook have to extend PreCommitInterdiction, so this method is available. Take a look:

protected String loadFileContents(String repositoryPath, String username, String password, String transaction, String filePath) throws PreCommitException
{
  File repo = null;
  SVNLookClient svnLook = null;
  String contents = null;
  try
  {
    repo = new File(repositoryPath);
    ISVNAuthenticationManager authenticationManager = BasicAuthenticationManager.newInstance(username, password.toCharArray());
    ISVNOptions svnOptions = new DefaultSVNOptions();
    svnLook = new SVNLookClient(authenticationManager, svnOptions);
  }
  catch (Exception ex)
  {
  log.error("Fail while connecting to SVN using \"" + username +  ": " + ex.getMessage(), ex);
  throw new PreCommitException("Unable to connect to SVN: " + ex.getMessage());
  }
  try
  {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    svnLook.doCat(repo, filePath, transaction, baos);
    contents = baos.toString();
  }
  catch (SVNException ex)
  {
    log.error("Fail while loading contents of \"" + filePath + "\": " + ex.getMessage(), ex);
    throw new PreCommitException("Unable to load contents of submitted file: " + ex.getMessage());
  }
  if (contents == null)
  {
    throw new PreCommitException("Contents loaded from file is invalid.");
  }
  
  return contents;
}
  • Line 286-289: connect to SVN repository
  • Line 298-300: read the contents of submitted file

If the instance is unable to connect to SVN or the file contents is unreachable or invalid, a PreCommitException is thrown.

At this point, we have walked for all Java implementation. The pattern is flexible and functional in any Operating System, I guess (I have not tested others than Windows). The source code is available on my GitHub as well entire solution including configurations files and scripts.

However, the Java application (hook) will not work without a little help. The SVN server doesn’t execute applications itself but shell scripts. Therefore, when using Windows as host of the SVN server (not as client) you need to write a couple of .bat or .cmd files to call your hooks.

To accomplish our current scenario are needed three scripts:

  • pre-commit.bat: responsible to call other scripts, in fact, everything could be written here
  • TickingClockHook.bat: call the hook responsible to validate filenames
  • BadLanguageHook.bat: call the hook responsible to validate each file’s contents

These scripts will work only in a Windows host. If you are running your SVN Server on Linux, you need to write bash scripts to do what they do above -it is not a big deal.

Finally, there are two files used to configure the execution:

  • log4j.xml: configuration of log messages
  • svn.properties: authentication parameters used by the hook to connect to SVN

Here we are! I hope this pattern help you to make things a little more organized in your projects.

Download the complete and functional project from my GitHub.


Creating rules dynamically with Drools

This “how to” walks through a solution to dynamically create and execute business rules.

rules

Why we need this

It’s common the necessity to implement some kind of rules to choose between one and other action. Often, these rules are expressed in a sort of business thinking. Drools is a Business Rules Management System maintained by Red Hat and JBoss, and the answer when we need a robust, flexible and open source solution!

What we need

  • JDK 1.7+
  • Drools 6.5+
  • Maven 3.0.5+

How to

First of all, is needed to understand what rules mean in this context. Each rule in Drools works like a if statement in a programming language, thus basically we have two parts; conditional and action. This is written by someone who understood the business rule and adapted it in the schema of Drools Language Rule:

rule "Apply 10% off over all items of $4 or more"
when
    Product(price >= 4.0)
then
    product.discount(10);
end

Pretty easy, right?!

Line 1 says the friendly name of the business rule.
Line 3 is the condition to satisfy. In this case, the price of product has to be equal or more than 4 bucks .
Line 5 shows the action to be executed, so apply 10% discount over product’s price.

We can write how many rules are needed and all of them are saved in a file with extension .drl. But, as a file it is static and the goal here is to create something dynamic, therefore writing files is not an option!

Hands-on mode

Let’s think about the supermarket where we work. It’s time for promotions and the manager asked for applying a set of discounts on some products.

  • Apply 10% off over all items of $4 or more
  • For all items with due date on next 7 days, apply 45%
  • Give 5% off over every kind of Beans

There we go…

Before starting code, just make sure to have the following dependencies in your project file pom.xml:

<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-compiler</artifactId>
  <version>6.5.0.Final</version>
</dependency>
<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-core</artifactId>
  <version>6.5.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
  <artifactId>drools-decisiontables</artifactId>
  <version>6.5.0.Final</version>
</dependency>

Next approach is to use Rule Templates, where we can write the pattern of our rules, and populate it after with concrete rules. Following is what we need to accomplish our mission, the file Product.drl:

template header

name
object
conditional
action

package drools.templates;

global net.itfromhell.howit.dummy.Product product;

import java.text.SimpleDateFormat;
import function net.itfromhell.howit.dynamicdrools.util.DroolsUtility.debug;

dialect "java"

template "Product"

rule "@{row.rowNumber} - @{name}"
when
  @{object}(@{conditional})
then
  product.discount(@{action});
  debug(drools);
end

end template

The structure used to create a template file is similar to regular rule file. Please, take a look on:

  • Line 1: describes this file as a template
  • Line 3-6: parameters expected in this template
  • Line 15: declares the dialect used as java
  • Line 19-25: rule defination
  • Line 27: end of template

Now we have a template to handle all rules about the products in promotion, the next step is to write a couple of rules describing how to apply the discount on them. We will do it programmatically, using a set of classes that I coded to make the dirty job:

  • Rule.class: encapsulate all that is needed to create one single business rule.
  • Condition.class: describe one specific condition to be evaluated.
  • DroolsUtility.class: tool to operate everything in memory.

The complete source code, compiling and ready for duty is available in my GitHub.

In my opinion, you wanna see everything working, who knows if it isn’t a joke… in this case, run ShowMeTheDrools.class:

public class ShowMeTheDrools
{
 public static void main(String args[]) throws Exception
 {
  //List to keep all rules
  List<Rule> rules = new ArrayList<Rule>();
  //Load each business rule
  rules.add(createDiscountOverpriced());
  rules.add(createDiscountSoonDueDate());
  rules.add(createDiscountBeans());

  //Create a session to operate Drools in memory
  DroolsUtility utility = new DroolsUtility();
  StatelessKieSession session = utility.loadSession(rules, "drools/templates/Product.drl");

  //Define the products to be processed using our rules
  Product blackBeans = new Product("Black Beans", 2.20, "30/12/2017");
  Product cannelliniBeans = new Product("Cannellini Beans", 4.15, "05/02/2018");
  Product kidneyBeans = new Product("Kidney Beans", 2.05, "20/11/2017");
  Product rice = new Product("Rice", 1.10, "28/10/2017");
  Product milk = new Product("Milk", 3.50, "10/11/2017");

  /*
  Now, the magic happens!
  For each product to be processed, we have to face it over rules to get, or not, a discounted price.
  */
  System.out.println("Applying over " + rice.getName() + " with price $" + rice.getPrice() + "...");
  session.setGlobal("product", rice);
  session.execute(rice);
  System.out.println("...price after review: $" + rice.getPrice());

  System.out.println("Applying over " + blackBeans.getName() + " with price $" + blackBeans.getPrice() + "...");
  session.setGlobal("product", blackBeans);
  session.execute(blackBeans);
  System.out.println("...price after review: $" + blackBeans.getPrice());

  System.out.println("Applying over " + milk.getName() + " with price $" + milk.getPrice() + "...");
  session.setGlobal("product", milk);
  session.execute(milk);
  System.out.println("...price after review: $" + milk.getPrice());

  System.out.println("Applying over " + kidneyBeans.getName() + " with price $" + kidneyBeans.getPrice() + "...");
  session.setGlobal("product", kidneyBeans);
  session.execute(kidneyBeans);
  System.out.println("...price after review: $" + kidneyBeans.getPrice());

  System.out.println("Applying over " + cannelliniBeans.getName() + " with price $" + cannelliniBeans.getPrice() + "...");
  session.setGlobal("product", cannelliniBeans);
  session.execute(cannelliniBeans);
  System.out.println("...price after review: $" + cannelliniBeans.getPrice());
 }

As result we got:

Applying over Rice with price $1.1...
Triggered rule: 1 - Apply discount on all soon due date
...price after review: $0.605

Applying over Black Beans with price $2.2…
Triggered rule: 2 – Discounting on all beans
…price after review: $2.0900000000000003

Applying over Milk with price $3.5…
…price after review: $3.5

Applying over Kidney Beans with price $2.05…
Triggered rule: 2 – Discounting on all beans
…price after review: $1.9474999999999998

Applying over Cannellini Beans with price $4.15…
Triggered rule: 2 – Discounting on all beans
Triggered rule: 0 – Give some discount on overpriced
…price after review: $3.5482500000000003

In order to verifiy the promotional price, we noted a discount on Rice which started for $1.1 and now is $0.605 (what bargain! don’t forget to check the due date). We know why, it’ s because the rule named “Apply discount on all soon due date” was triggered applying its huge discount.

Black Beans started from $2.2 and finished to $2.09, 5% less because of rule “Discounting on all beans”.

But wait, we got no discount on Milk since the start and final prices are the same 3.5 buks! The simple answer is just because no rule was triggered (you can check it).

Something different happened to Cannellini Beans, there are two rules triggered, is it right? Yes it is. The first rule about Beans is triggered applying 5%, next the rule about overprice is triggered applying more 10%, so the final price is now $3.54. It is intersting since we are able to chain rules, increasing the complexity of our solution.

Back to source code of ShowMeTheDrools on lines:

  • 25-27: all three business rules are created (next section we see details)
  • 31: our tool is used to get a session to operate rules
  • 34-38: a set of products is defined
  • 44-67: we submit each product against all business rules and watch what happens on price

To make it easy to understand, I created a specific method for each business rule. In the real world it doesn’t make any sense. Anyway, let’s see how it works for asked business rule “Apply 10% off over all items of $4 or more”:

private static Rule createDiscountOverpriced()
{
 //First of all, we create a rule giving it a friendly name
 Rule rule = new Rule("Give some discount on overpriced");
 //Here we need to say what kind of object will be processed
 rule.setDataObject(Product.class.getName());

 //As expected, a rule needs condition to exists. So, let's create it...
 Condition condition = new Condition();
 //What data, or property, will be checked
 condition.setProperty("price");
 //What kind of check to do
 condition.setOperator(Condition.Operator.GREATER_THAN_OR_EQUAL_TO);
 //What is the value to check
 condition.setValue(new Double(4.0));

 //Next, is needed to set rule's condition
 rule.setCondition(condition);
 //Finally, this is what will be done when ours condition is satisfied
 rule.setAction("10");

 return rule;
}

What about “For all items with due date on next 7 days, apply 45%”:

private static Rule createDiscountSoonDueDate() throws Exception
{
 Rule rule = new Rule("Apply discount on all soon due date");
 rule.setDataObject(Product.class.getName());

 //Is possible to create multiple conditions, therefore, data range or more complex situations could be expressed
 Condition greaterThan = new Condition();
 greaterThan.setProperty("dueDate");
 greaterThan.setOperator(Condition.Operator.GREATER_THAN);
 greaterThan.setValue((new SimpleDateFormat("dd/MM/yyyy").parse("23/10/2017")));

 Condition lessThan = new Condition();
 lessThan.setProperty("dueDate");
 lessThan.setOperator(Condition.Operator.LESS_THAN);
 lessThan.setValue((new SimpleDateFormat("dd/MM/yyyy").parse("30/10/2017")));

 //You can define as many as necessary conditions to achieve your necessity
 rule.setConditions(Arrays.asList(greaterThan, lessThan));
 rule.setAction("45");

 return rule;
}

Finally we have the third business rule “Give 5% off over all Beans”:

private static Rule createDiscountBeans()
{
 Rule rule = new Rule("Discounting on all beans");
 rule.setDataObject(Product.class.getName());

 //This is the simplest way to define the rule' condition
 rule.addCondition("name", Condition.Operator.CONTAINS, "Beans");  

 rule.setAction("5");

 return rule;
}

Let’s take a look over most important pieces of code of each class, starting from beggining; Rule.class

As we discussed before, the engine understand Drools Rule Language, the method conditionAsDRL transforms all conditions of the rule into textual expressions.

 public String conditionAsDRL() throws IllegalStateException, IllegalArgumentException
 {
  if ((conditions == null) || (conditions.isEmpty()))
  {
   throw new IllegalStateException("You must declare at least one condition to be evaluated.");
  }

  StringBuilder drl = new StringBuilder();
  //For each condition of this rule, we create its textual representation
  for (int i = 0; i < conditions.size(); i++)
  {
   Condition condition = conditions.get(i);
   drl.append("(");
   drl.append(condition.buildExpression());
   drl.append(")");
   if ((i + 1) < conditions.size())
   {
    drl.append(" && ");
   }
  }

  return drl.toString();
 }

The class Condition.class has buildExpression, executed by Rule and responsible to return its own expression of the conditional.

public String buildExpression() throws IllegalArgumentException
{
 StringBuilder drl = new StringBuilder();

 if (value instanceof String)
 {
  drl.append(expressionForStringValue());
 }
 else if (value instanceof Number)
 {
  drl.append(expressionForNumberValue());
 }
 else if (value instanceof Date)
 {
  drl.append(expressionForDateValue());
 }
 else
 {
  throw new IllegalArgumentException("The class " + value.getClass().getSimpleName() + " of value is not acceptable.");
 }

 return drl.toString();
}

For each type of value, there is a specific method responsible to create the specialized expression, as exemple of expressionForNumberValue, used to transform a Number instance:

private String expressionForNumberValue() throws IllegalArgumentException
{
 StringBuilder drl = new StringBuilder();

 if ((operator.isComparable(Short.class)) || (operator.isComparable(Integer.class)) || (operator.isComparable(Long.class))
     || (operator.isComparable(Double.class)) || (operator.isComparable(Float.class)))
{
  drl.append(property).append(" ").append(operator.getOperation()).append(" ").append(value);
 }
 else
 {
  throw new IllegalArgumentException("Is not possible to use the operator " + operator.getDescription() + " to a " + value.getClass().getSimpleName() + " object.");
 }

 return drl.toString();
}

Last but not less important, the class DroolsUtility.class has two methods to see:

/**
 * Loads a session to execute rules in memory using a template file.
 *
 * @param templatePath Relative path to template file describing the rule's pattern.
 * @param rulesAsParameters List of maps representing each rule as a set of parameters.
 * @return Session for execution of rules.
 * @throws Exception
 */
private StatelessKieSession loadSession(String templatePath, List<Map<String, Object>> rulesAsParameters) throws Exception
{
  ObjectDataCompiler compiler = new ObjectDataCompiler();
  //Compiles the list of rules using the template to create a readable Drools Rules Language
  String drl = compiler.compile(rulesAsParameters, Thread.currentThread().getContextClassLoader().getResourceAsStream(templatePath));

  System.out.println("drl:\n" + drl);

  KieServices services = KieServices.Factory.get();
  KieFileSystem system = services.newKieFileSystem();
  system.write("src/main/resources/drools/templates/rule.drl", drl);
  services.newKieBuilder(system).buildAll();

  KieContainer container = services.newKieContainer(services.getRepository().getDefaultReleaseId());
  StatelessKieSession session = container.getKieBase().newStatelessKieSession();

  return session;
}

The highlight line 56 is a trick, it will print in console the concrete generated .drl‘s contents, which is used by the engine in memory. See below:

package drools.templates;
global net.itfromhell.howit.dummy.Product product;
import java.text.SimpleDateFormat;
import function net.itfromhell.howit.dynamicdrools.util.DroolsUtility.debug;
dialect "java"

rule "2 - Discounting on all beans"
when
  net.itfromhell.howit.dummy.Product((name.toUpperCase().contains("BEANS")))
then
  product.discount(5);
  debug(drools);
end

rule "1 - Apply discount on all soon due date"
when
  net.itfromhell.howit.dummy.Product((dueDate > (new SimpleDateFormat("dd/MM/yyyy HH:mm:ss")).parse("23/10/2017 00:00:00")) && (dueDate < (new SimpleDateFormat("dd/MM/yyyy HH:mm:ss")).parse("30/10/2017 00:00:00")))
then
  product.discount(45);
  debug(drools);
end

rule "0 - Give some discount on overpriced"
when
  net.itfromhell.howit.dummy.Product((price >= 4.0))
then
  product.discount(10);
  debug(drools);
end

As suggests its name, this method can be used to get some details of the triggered rule when the engine acts.

/**
 * Debug tool to show what is happening over each triggered execution.
* Name of rule trigger as well the object inspected are printed.
 *
 * @param helper Injected when a consequence is fired.
 */
public static void debug(final KnowledgeHelper helper)
{
 System.out.println("Triggered rule: " + helper.getRule().getName());
 if (helper.getMatch() != null && helper.getMatch().getObjects() != null)
 {
  for (Object object : helper.getMatch().getObjects())
  {
   System.out.println("Data object: " + object);
  }
 }
}

That’s all folks!

Remember it: living on your own rules 🙂

Download the complete project from my GitHub.


The danger of persistence of decision-making in project management

Recently I’ve been talking to a colleague, during a happy hour, about good projects that lead to bad results. Despite the fact that in happy hour meetings one isn’t supposed to talk about work, the conversation brought some good reflections.

Gize Piramides

If the pyramids were software, the ones in the front would be the beta version

Since the time I attended high school in data processing – long seventeen years ago – I already looked at the numbers regarding information-system projects as a laughingstock. I remember one of my professors at that time comparing software engineering with civil engineering, invariably praising the management and construction capability of civil engineering in relation to software engineering. Anyway, civil engineers started building the pyramids five thousand years ago, we barely started punching cards a bit over fifty years ago. Historically, they are way ahead of us – I used to think.

Returning to the subject, this colleague used to talk about a project of which he was the manager, and which potentially represented an important evolution in the Company, but that at last was becoming a millionaire failure. My insane curiosity did not cease to be teased in order to understand, after all, why there was such a discrepancy between what was planned and what was achieved.

That project, with a budget of almost one and a half million reais, met four of the five classic reasons for initiation: strategic need, market demand, client request and technological advance. Not only fit to meet the legal requirements. Avoiding further discussion on so many other details, especially for ethical reasons, I can say that the project that was the subject of our discussion was interesting and promising. But then, what failed?

Chaos Report 2009

Chaos Report 2009

According to the 2009 Chaos Report published by Standish Group, 32% of IT projects were successful – within the deadline, budget, scope, and quality (!). In a comparison with the previous report published in 2006, the percentage fell by three points, when it was 35%. Even so, the scenario improved a lot, because at the time I was in high school, the 1998 report showed a 26% success rate.

We can certainly point out many reasons why so many projects have failed (if we built bridges, imagine that 68% of them fell). Here we will just focus on my colleague’s project. Of all this sad story, what caught my attention, and that could even be left in the background, was the direct intervention of the IT Director during the procedures for the selection of suppliers. After defining the necessary acquisitions, and passing through the ritual of proposal requisitions, the project team classified the suppliers and identified the one that best met the requirements defined at the beginning of the process. Although it is questionable, the final decision as to which supplier would be contracted was the Director’s, and he decided for the supplier with the lowest cost and biggest risk (according to the team reports). This is where my particular analysis begins, not to question the decision tree of my colleague’s company – who said it is questionable? – but to draw a parallel to the interesting psychological theory of the “freezing effect”, grounded by Kurt Lewin after World War II.

Kurt Lewin

Kurt Lewin has grounded the Three Step Theory

After the Director’s decision to hire the least suitable supplier, according to the project team, the software development work began. It was not long before problems of quality and timing began, and at first they were bypassed within project management. With time and the persistence of occurrences, timeline milestones remained disregarded, and reports were issued with alternative solutions and their projected scenarios defined. Finally, the management team directly called on the Director to make a decision regarding the supplier. In the first foray, the decision was for the maintenance of the supplier, and a discreet request for the latter’s attention. There were still other three or four rounds, where the same process of identification, creation of options, and decision making was repeated, always with the same result; the maintenance of the supplier. Or would it be the maintenance of the decision?

People tend to adhere to their own decisions, promoting the maintenance of the commitment to the first decision, in an escalation of decisions. This helps to explain why the Director kept his decision for that supplier, even though he had access to reports that advised against it. The decision for the supplier selection was deliberately his. This first decision is the foundation of the “Escalation of Commitment” effect (Barry M. Staw, 1976). According to the psychological theory, the initial decision freezes the system of possible choices of the individual, causing him to focus on committing himself to the behavior that makes more sense to his decision. After all, this is the common and expected behavior of people, because in an organized society what would happen if everyone started behaving one way after having committed to another? Therefore, this effect is a basic block in the construction of personality.

Just as the Freeze Effect process explains the Director’s attitude in maintaining his decision, it also explains why the project management team, after analyzing the supplier’s performance, was able to seek solutions and even to suggest the replacement of the supplier: the original decision was not theirs. Without commitment to the decision, the team was free to use rationally the information obtained. It is especially interesting to understand that this psychological phenomenon exists and how it works so that we can manage it and seek ways to prevent its perverse effects by exploring and maximizing its virtues.

Of course my colleague’s episode is not an exception, as the Chaos Report figures prove. With even more certainty, not all projects have problems with suppliers. Information system projects have so many points of attention that an IT project manager should be promoted to a god (a bit of chauvinism). What is important to extract from this tale is the lesson.

As the freezing effect comprises the Escalation of Commitment, two other concepts are also related: the Irreversible Expense and the Trap.

I can imagine that at a certain moment, while presenting themselves to the Director, the project management team suggested replacing the supplier. The Director, on the other hand, must have argued – with more or less emotion – that the project had already spent financial resources with said supplier and therefore would not be prudent to replace it. This is an example of the judgment by Irreversible Expense, the phenomenon that occurs when the individual persists in the decision because he had previously invested money, time, effort, in detriment of other decisions, which had potentially more advantages.

It is worth remembering that the hypothetical manual of good project management says that in deciding for the continuity of the project, efforts which have already been made must not be considered (these costs are sunk in the accounting norm). Therefore, a good project management, in itself, should be enough to prevent the Irreversible Expense phenomenon from contaminating the decision making.

And as far as timeline milestones are concerned, isn’t it one of their functions to serve as a checkpoint to help control the project? Yes, but, perhaps they were not used satisfactorily. The last phenomenon, the Trap, can help the understanding of how to improve the use of those milestones. Who knows, maybe in my colleague’s project, this concept could have helped correct the course, and ensured that the end result was the one intended.

Prompt to continue with the project

What now?

An experiment conducted in 1979 by Joel Brockner, Myril C. Shaw and Jeffrey Z. Rubin, showed that players who were exposed to the opportunity to decide whether to continue or stop betting, lost less when they were forced to decide to continue. On the other hand, those who, on the same occasion, would only act if they decided to stop, lost more.

The timeline milestone generally works as the first case of the cited experiment. There is a milestone, where the opportunity for decision occurs. If a strong decision is not taken, the project will continue automatically. Like the bettor who loses more, the project remains consuming more resources, even if it is out of control. The lesson learned comes in here, as it would be enough changing the way the timeline milestone works so that the initial decision Trap is controlled. Thus, at each milestone of the project, if there is no decision, the project is then discontinued. Radical? Perhaps. Now, think about the resources that would be saved in exchange for more aggressive management.

In this conversation with my colleague, and consequently in the reflection of the case he presented, I did not expect to discover the philosophical stone of project management. But I was glad that we understood human psychology a little more, and how it guides us in a subtle and transparent way.


Spring Framework marks transaction to rollback when everything is fine

Eventually, you can’t conclude the whole process flux because, at the end, the Spring Framework marks the transaction to rollback, even when all exceptions were caught.

The evidence of this scenario is this following message Transaction was marked for rollback only; cannot commit. The exception thrown is org.springframework.orm.jpa.JpaSystemException.

It happens because in some point of all code processed, your flow had an exception unchecked. The simplest solution is to use checked exceptions and avoid use NoResultException unless it is really necessary.


Generating client for SOAP using CXF

What is needed

  • WSDL file describing the services
  • Apache CXF (3.1+)
  • JDK (1.7+)

Straight to point

In order to create the set of Client’s classes, verify for the following environment variables:

  • JAVA_HOME: Path to JDK location, eg. C:\Progra~1\Java\jdk1.7.0_80
  • CXF_HOME: Path to CXF location, eg. C:\Java\apache-cxf-3.1.13

Now, open a command prompt and execute the command: wsdl2java.bat -p net.itfromhell.itsatrap.serviceclient -d C:\Temp\TestClient -all -ant -exsh false -dns true -dex true -encoding UTF-8 -verbose Test.wsdl

Where…

  • wsdl2java.bat: Tool to generate encapsulated service’s client from WSDL document
  • net.itfromhell.itsatrap.serviceclient: Package of generated classes
  • C:\Temp\TestClient: Output directory to generated classes
  • Test.wsdl: WSDL file

PWC6345: There is an error in invoking javac.

Accessing your application in GlassFish you get this error message:

org.apache.jasper.JasperException: PWC6345: There is an error in invoking javac. A full JDK (not just JRE) is required

Try to verify the parameter AS_JAVA inside of file glassfish\config\asenv.bat(.conf). This parameter should be the JDK path.


Get access to DAS for other Domain than default using shell

Need to access your GlassFish as administrator but in other Domain than default. Use the tool asadmin, to do that you need to specify the port of DAS to this specific Domain:

asadmin --host localhost --port 4848 enable-secure-admin

Error setting expression ‘X.Y’ with value ‘[Ljava.lang.String;@6791525e’

If you get this error message:

[OgnlValueStack]: CommonsLogger.warn{60} Error setting expression ‘X.Y’ with value ‘[Ljava.lang.String;@6791525e’

Try changing the order of setter method is implemented, move to first sequence the method with String as a parameter.


A irracionalidade à serviço da racionalidade na tomada de decisão

A decisão compartilhada, ou em grupo, é uma das pedras fundamentais da civilização ocidental moderna, a própria democracia tem como base este conceito. Mas até onde grupos tomam a melhor decisão? O quanto do objetivo esperado –enquanto decisão do grupo- é obtido em um comitê de aprovação do projeto ou na reunião de equipe para validar o cronograma?

No reino de Arthtur, as decisões eram compartilhadas pelos iguais

No reino de Arthtur, as decisões eram compartilhadas pelos iguais

Diz a lenda que o Rei Arthur possuía uma mesa de reuniões redonda, a Távola Redonda, onde todos eram iguais e portanto participavam igualmente das decisões ali tomadas. Na empresa em que trabalhamos, gostamos da ideia de participar dos eventos relevantes, incluído aí a tomada de decisão, este é o desejo natural pela democracia, ainda que uma empresa não seja uma instituição democrática.

A tomada de decisão em grupo nas empresas é uma teoria administrativa que mira em diversas vantagens como o aumento da satisfação no local de trabalho, a motivação propiciada pela participação, e que por fim resulta no clima organizacional positivo bem como no aumento de produtividade. O conceito popular de que “muitas cabeças pensam melhor do que uma” pode materializar-se em decisões com níveis de qualidade superiores aquelas decisões individuais. Apenas ainda não sabemos o que fazer com a percepção de que a tomada de decisão em grupo pode ser improdutiva e frustrante ao desperdiçar tempo -e dinheiro.

Max Gehringer, administrador de empresas e escritor, autor do livro Clássicos do Mundo Corporativo, diz em seu artigo As Sete Regras do Manual do ‘nunca’ para projetos: “nunca tente convencer, se você pode mandar”.

Existe um aspecto macabro da tomada de decisão em grupo e que é inerente ao principal ator em palco, o ser humano. Em 1964 um experimento liderado

The Milgram's Experience

A experiência de Milgram: E=Experimentador, S=Sujeito, A=Ator

pelo psicólogo Stanley Milgram colocou um grupo de voluntários em uma sala em que do outro lado, separado por uma fina parede, um dos voluntários selecionado aleatoriamente era posicionado sentado e amarrado a cadeira. A cada pergunta feita pelo pesquisador ao homem, e que este errasse a resposta, o grupo deveria pressionar um botão que infringiria a ele um choque elétrico. No início os choques eram leves e rápidos, mas com o tempo se tornaram fortes e intensos –em paridade com os gritos do voluntário. Por fim, após um longo choque, o homem emudeceu e o mal estar tomou conta do ambiente. Naturalmente este era um experimento, e o homem, um ator de verdade, nunca levou qualquer choque. O importante na pesquisa foi a constatação de que o grupo perdia a sensação de responsabilidade –no caso, para com a punição-, já que a decisão tomada era do “grupo” e não do individuo. Um teste de controle mostrava que sendo uma decisão individual, os participantes não infringiam tal nível de choque elétrico ao pobre homem.

Free Vermeulen

Freek Vermeulen, autor de Business Exposed

O professor da London Business School e autor do livro Business Exposed, Freek Vermeulen, fala sobre a inclinação das pessoas em imitar o comportamento dos outros. De fato este talvez seja um dos nossos primeiros impulsos, e o responsável por aprendermos a falar, andar e… a tomar decisões. É fácil imaginar uma reunião para tomada de decisão onde o primeiro a se aventurar em opinar é seguido pelos demais, enquanto outro grupo simplesmente se omite. Alias, a omissão é explicada por Freek como uma inibição e não como um sinal de concordância; “quem cala consente”. O fato é que ninguém gosta de ser a minora, seja torcendo por um time de futebol ou durante uma decisão importante na Companhia. “A consequência disso é que, numa reunião, pode ocorrer de todos estarem divergindo, mas ninguém se manifestar por relutância“, afirma o professor.

Então o que fazer com a decisão compartilhada, agora que a endemoniamos? Algumas vezes é necessário derrubar paredes para construir alicerces. Então vamos saber extrair da decisão compartilhada o seu melhor e da melhor maneira, a fim de garantir que em um comitê de aprovação do projeto, ou na reunião de equipe para validação –e naturalmente aprovação- alcancemos o comprometimento e a maturidade superiores.

Norman Maier, psicólogo experimental americano, defende o método da decisão em grupo na prática do comando eficaz. Em seus estudos, Maier leva em consideração duas dimensões. A primeira é o peso social interno, e a segunda é o peso na eficiência organizacional. Criando uma matriz destas duas dimensões, poderemos encaixar cada decisão em um quartil. Maier concluiu que é possível diminuir sensivelmente os vícios da decisão compartilhada ao eleger um “animador profissional”.

Maier's Matrix

Matriz imaginária de Maier para modelo de decisão

Esta figura é responsável por manter elevado o nível da discussão, valorizando a esfera da informação e conduzindo de forma habilidosa à escolha de uma solução. O animador profissional tem lugar nas decisões críticas, onde o espaço para a manobra é reduzido, e o grupo não pode decidir além de determinados limites. Há mais um aspecto nesta forma de tomada de decisão, obter uma decisão que não é uma decisão. O animador manipula o grupo para uma decisão mais ou menos predeterminada, dando palavra à pessoa certa, suspendendo a reunião, ou declarando a reunião terminada no minuto oportuno. Habilidade é essencial para realizar tudo isto sem que os membros tenham percepção de manipulação enquanto se obtém o melhor do processo de resistência a mudanças, a “aceitação das consequências da decisão”.

Manhattan Connection guys

Comentaristas do programa Manhattan Connection. Lucas Mendes (ao centro) é exemplo de animador profissional de Maier

O modelo sugerido por Maier me faz lembrar muito o programa Manhattan Connection, exibido no canal pago Globo News. No ar a 19 anos, comentaristas políticos, econômicos e culturais debatem sobre diversos destaques da semana. Uma mesa de discussão por vezes caótica, mas que é habilmente coordenada pelo jornalista Lucas Mendes, que faz o papel de animador profissional trazendo o assunto e direcionando a discussão até obter (quase sempre) o resultado. Resultado que se pode imaginar de antemão ser o esperado.

Planejar a tomada de decisão compartilhada, e realizar o processo de uma forma menos ortodoxa, pode tornar fácil implementar um bom sistema decisório. O esforço despendido na atividade é recompensado com motivação, participação e comprometimento dos envolvidos na concretização prática da decisão.