Would you like to present at Agile 2012 Conference?

I am producing the Agile Development Practices Stage with my Co-producer, Chirag Doshi at the Agile India 2012 conference to be held in Bangalore.

Here is the brief description of the stage -
Being agile and realizing success requires being committed and applying certain set of practices continuously and sincerely. How we behave, how we communicate, the set of practices we follow all affect our results. We will focus on technical, sociological, and other practices that affect and influence the ability of individuals and of the teams to attain agility and realize success in their development activities. We will learn real tried and tested practices from practitioners who have gained hands-on experience from real life projects and have the ability, willingness, and passion to share those with us.

Today almost every company is agile, but not everyone is succeeding with it. What sets the winners apart? There are some overarching principles, however, success comes from day-to-day activities, behavior of individuals and teams, how they interact, how they react, and how they foster a conducive environment for success. All the principles we can learn is of little use if we don't practice sincerely and pragmatically to realize the results. This stage will help developers share practices from their real-life experience, things that worked for them, why, how, and to what extent they used and should be used. Would you like to share with other practitioners? To know more about submitting a proposal, please go through http://agileindia2012.agilealliance.org/for-speakers and submit your proposal using the submission system.

If you have a topic that does not suit this stage, you can submit your proposal to other stages.

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [0]

Calling for Stage Proposals for Agile India 2012 Conference...

Agile Alliance is organizing the largest Agile conference in India called Agile India 2012 -- http://bit.ly/r7nfzw. The conference will be hosted in Bangalore, India around 2nd week of Feb 2012.

Visit http://agile2012.in to submit your stage proposals.

Please read the Stage Producer's FAQ Sheet -- http://bit.ly/penVO1 for more details about the responsibilities of a Stage producer.

Hurry! The last date for submitting stage proposals is 14th Aug.

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [0]

Kill That Util Class!

According to me a Util class is a sign of misplaced responsibility (a missed opportunity to see an abstraction fulfilling that behavior), resulting in poor OO-ness. Often, utility methods are placed in classes with only static methods and disallow instance creation with new. If you listen carefully, these Utility classes cry out loud, telling you to find a home for the homeless child!

In Java, we have so many examples, number one in that Util-Anti-Pattern parade, IMO is the Math class itself...why can't operations like abs, max, min exist on the Number abstraction itself?

Parading open source Java libraries, you will find various utilities, for example, the Apache Commons Lang's, StringUtils augments the functionality that the String could have provided out-of-the-box...well, one can argue String is a final class and hence StringUtils. But why have DateUtils, when java.util.Date is not final?

Whether final classes or non-final, underlying language can atleast provide some hook that would help us supplement behaviors to preserve OO-ness. As of Java6, I don't know of any such mechanism that can do that, hence we see the Util-Anti-Pattern proliferation, but that can limit to library classes (including Java libs) while avoiding it on custom objects as the source code is under your control.

Various Languages like Groovy, C#, Ruby etc... allow you to create hooks and attach them to supplement the behavior of an object, thus preserving OO-ness of the design. Lets take the case of String, which is a final class in Java and try to add a behavior on to the String class using Groovy.

String.metaClass.isPalindrome = { ->
	delegate == delegate.reverse()
}

word = "Groovy"
println "Is $word a Palindrome? ${word.isPalindrome()}"

word = "madam"
println "Is $word a Palindrome? ${word.isPalindrome()}"

In C# 3.0, one can use Extension Methods to achieve this.

using System.Text;

namespace Com.Tsys.Extensions
{
    public static class StringExtension
    {
        public static string Reverse(this string str)
        {
            var length = str.Length;
            var reverse = new StringBuilder(length);
            for (var i = length - 1; i >= 0; i--)
            {
                reverse.Append(str[i]);
            }
            return reverse.ToString();
        }

        public static bool IsPalindrome(this string str)
        {
            return str.Equals(str.Reverse());
        }
    }
}

//Client Code
var word = "CSharp";
Console.Out.WriteLine("word = {0}", word);
Console.Out.WriteLine("word.Reverse() = {0}", word.Reverse());
Console.Out.WriteLine("word.IsPalindrome() = {0}", word.IsPalindrome());

word = "madam";
Console.Out.WriteLine("word = {0}", word);
Console.Out.WriteLine("word.Reverse() = {0}", word.Reverse());
Console.Out.WriteLine("word.IsPalindrome() = {0}", word.IsPalindrome());

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [13]

CSI Convention Goa

Yesterday I spoke at the Computer Society of India (CSI) convention in Goa. Participants were largely graduating students from final years. For this session, the problem was the same which I used during the XP Days, Indore, however instead of Java, I used C# as the programming language to explain and drive OO design through tests.

It was an enjoyable session and I found that quite a few students where aware of JUnit and were able to appreciate how the design evolved in the due course from a procedural solution to a OO solution. Though for some it went a bit over board, probably because either they were not familiar or not seen something like this before. What I'd say, metaphorically is, just like a farmer, ploughing the field, I'd hope that, the talk would have done the spade work and then its really up to them to sow the seeds, water it and watch the crops grow. I'd like to thank Prof. Ramrao, Goa University for inviting me over and taking good care.

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [4]

Grails: Binding Domain Objects for Controllers to use

On this current Grails project of mine, all our controllers have closures for save, update, delete etc... as we needed to do more in our views and controllers, rather than depend on vanilla Grails scaffolding. So, on each of our controller, we would have a boilerplate code to fetch object from database (on Update/Delete) or create new (upon Save) and almost all the controllers had code like the below in the save, update and delete actions:
class AuthorController {

  def scaffold = Author

  def save = {
    def authorInstance = new Author()
    authorInstance.properties = params
    // ...
    authorInstance.save()
  }
  def update = {
    def instanceId = params.id as Integer
    def authorInstance = Author.get(instanceId)
    authorInstance.properties = params
    // ...
    authorInstance.save()
  }
  def delete = {
    def instanceId = params.id as Integer
    def authorInstance = Author.get(instanceId)
    authorInstance.properties = params
    authorInstance.delete()
  }
}

Obviously, this is a lot of boilerplate code to write every time for each controller, its time to refactor this. The standard idea is to make the authorInstance already available for further operations in the AuthorController. This means some where in the flow, before the controller gets called we need to either fetch or create a domain object instance and make it available for use in the controller. Filters in Grails sound like a good place to do this and especially the 'before' closure that gets invoked before the controller action is invoked. Secondly, the request scoped params seems like a good place to bind the created/fetched domain object instance for the controller to use. So, the controller code would now reduce to

class AuthorController {

  def scaffold = Author

  def authorInstance

  def save = {
    authorInstance = params.authorInstance
    // ...
    authorInstance.save()
  }
  def update = {
    authorInstance = params.authorInstance
    // ...
    authorInstance.save()
  }
  def delete = {
    authorInstance = params.authorInstance
    authorInstance.delete()
  }
}

For this to happen, I wrote a DomainObjectBindingFilters, where in for all the actions like 'save','delete' and 'update', domainObject instance would get binded, if the domainObject happens to be in the list of bindable domain objects, then based on the action say 'update' and 'delete' go ahead try to fetch that object from database, else for 'save' create a new instance and return that.

Once the instance is available, bind the fields from the request to objects properties and then finally use the 'params' to store the instance for the controller to use. The domain object instance can be stored using the standard grails naming convention (used by scaffolding code as well). Here is the code.

class DomainObjectBindingFilters {
  def bindableActions = ['save','delete', 'update']
  def bindableDomainObjects = [] //Add Domain Objects here	                         
  def controllerNames = toControllerNames(*bindableDomainObjects)
	                         
  def filters = {
    domainObjectBinder(controller:'*', action:'*') {
      before = {
        if (canBind(actionName, controllerName)) {
          def objectClass = bindableDomainObjects.find { bindableDomainObject ->
            def objectSimpleName = controllerName[0].toUpperCase() + controllerName[1..controllerName.length() - 1]
            bindableDomainObject.simpleName == objectSimpleName
          }
          if(objectClass) {
            def objectInstance = getInstance(objectClass, params.id)
            // Bind 
            objectInstance.properties = params
            def objectInstanceName = "${controllerName}${grailsApplication.config.grails.scaffolding.templates.domainSuffix}"

            //Store
            params[objectInstanceName] = objectInstance
          } else {
            println "You seem to have forgotten to include the Domain Object for ${controller} in ${this.getClass().name}"
          }
        }
      }
    }
  }

  def getInstance(objectClass, instanceId) {
    if (instanceId) {
      try {
        return objectClass.get(params.id as Integer)
      } catch (Throwable problem) {
        throw new ObjectNotFoundException(problem.message)
      }
    } else {
      return objectClass.newInstance()
    }
  }
	
  def toControllerNames(Class ...classes) {
    classes.collect { klass ->
      def className = klass.simpleName
      className[0].toLowerCase() + className[1..className.length() - 1]
    }
  }
	
  def canBind(actionName, controllerName) {
    bindableActions.contains(actionName) && controllerNames.contains(controllerName)
  }
}

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [0]

Object Initializers: An alternative to Test Data Builders

In Java6/C#2.0, I have used test data builders many a times for creating objects for tests. Using a builder encapsulates object creation within itself, so that you don't see naked constructor calls at various places in the tests and moreover do the chore of using the correct constructor (if there are multiple) and passing all the required collaborators/initial values in it for the it to be set-up correctly.

In a nutshell, builders shield you:

  1. when the constructor gets refactored (add/remove parameter), so you don't have to refactor every test
  2. from adding many flavors of constructors for setting up the object differently.
See http://nat.truemesh.com/archives/000714.html for further information

Lets take the example of a Person object creation in Java:
public class Person {
  private String name;
  private int age;
  private Address homeAddress;
}

public class Address {
  private string house;
  private string street;
  private string state;
  private string country;
}
Person person = new PersonBuilder()
                .withName("Some Name") 
                .withAge(60)
                .withHomeAddress(new AddressBuilder()
                         .withHouse("#45")
                         .withStreet("Some Street")
                         .build())
                .build();

Here are the corresponding builders for the Person and the Address class.

public class PersonBuilder {
  private String name;
  private String age;
  private Address homeAddress;

  public PersonBuilder withName(String name) {
    this.name = name;
    return this;
  }

  public PersonBuilder withAge(String age) {
    this.age = age;
    return this;
  }

  public PersonBuilder withHomeAddress(Address homeAddress) {
    this. homeAddress = homeAddress;
    return this;
  }

  public Person build() {
    Person person = new Person(name);
    person.setAge(age);
    person.setHomeAddress(homeAddress);
    return person;
  }
}

Languages like Groovy, C# provide constructs for initializing objects differently. This in my opinion alleviates the need for using a builder pattern to create objects that are required with different set-up values. For example, the above can in Groovy, be written in atleast 3 different ways, choose whichever on your personal taste:

class Person {
  string name
  int age
  Address homeAddress
}

class Address {
  string house
  string street
  string state
  string country
}
Here are different ways in which one can initialize object in Groovy (very flexible)
//I. Creating Object using Named Parameters
def person = new Person(name:'Dhaval Dalal', 
                        age:60, 
                        homeAddress:new Address(house:'#45', 
                                                street:'Some St.', 
                                                state:'NY', 
                                                country:'US'))
println "Person From Object Initializer = ${person}"

//II. Creating Person using the with or the identity closure
def address = new Address()
address.with {
  house = '#45', 
  street = 'Bergemont', 
  state = 'NY', 
  country = 'US'
}

def person = new Person()
person.identity {
  name = 'Dhaval Dalal'
  age = 60
  homeAddress = address
}

println "Person from with/identity closure = ${person}"

//IIIa. Creating Object from Map 
Person person = [name:'Dhaval Dalal', 
              age:60, 
              homeAddress:[house:'#45', 
                           street:'Some St.', 
                           state:'NY', 
                           country:'US'] //Implicit type conversion for address
             ]
println "Person From Map = ${person}"

//IIIb. Creating Object from Map (using operator 'as')
def person = [name:'Dhaval Dalal', 
              age:60, 
              homeAddress:[house:'#45', 
                           street:'Some St.', 
                           state:'NY', 
                           country:'US']
             ] as Person
println "Person From Map = ${person}"
Here is the equivalent, C# 3.0 Code:
new Person()
{
  Name = "Dhaval Dalal",
  Age = 60
}

new Person()
{
  Name = "Dhaval Dalal",
  Age = 60,
  HomeAddress = new Address()
  {
    House = "#45",
    Street = "Some Street",
    State = "Some State",
    Country = "Some Country"
  }
}
public class Person
{
  public int Age { get; set; }
  public string Name { get; set; }
  public Address HomeAddress { get; set; }
}

public class Address
{
  public string House { get; set; }
  public string Street { get; set; }
  public string State { get; set; }
  public string Country { get; set; }
}
I'd say that Groovy offers more alternative to construct objects as compared to C#.

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [1]

Avoiding Action closure proliferation on Grails Controller

On this current Grails project of mine, we needed to send to backend systems hearbeat messages every 5 seconds notifying them of our lively existence! But, we also needed a way to pause and resume sending those heartbeats, So I ended up coding in a simple HeartBeatJobController with the usual index.gsp, pause.gsp and resume.gsp, obeying the Grails convention.
class HeartBeatJobController {
	
  def heartBeatJobControllerService
	
  def index = {
    [status:"Sending Hearbeats is ${heartBeatJobControllerService.IsRunning()?'ON':'OFF'}"]
  }

  def pause = {
    heartBeatJobControllerService.pause()
    [status:'Sending HeartBeats has been Paused']
  }

  def resume = {
    heartBeatJobControllerService.resume()
    [status:'Sending HeartBeats has been Resumed']
  }
}
After I wrote it and got it to work, I said look at the duplication of invoking a operation and returning the status on the page and the fall-out proliferation of the action closures for each operation on the HeartBeatController....Hmmm, time to refactor. What if I can get rid of the closures pause and resume and use the method name as a request parameter? So earlier if I could pause, resume and view the status of hearbeat controller using the following URLs:
  • http://localhost/appName/heartBeatJob/
  • http://localhost/appName/heartBeatJob/pause
  • http://localhost/appName/heartBeatJob/resume
It would now change respectively to
  • http://localhost/appName/heartBeatJob
  • http://localhost/appName/heartBeatJob?operation=pause
  • http://localhost/appName/heartBeatJob?operation=resume

Thanks to Groovy's reflection Api (without elaborate chores like in Java), I just refactored the HeartBeatJobController to a single action closure (index) and got rid of pause.gsp and resume.gsp pages.

class HeartBeatJobController {
	
  def heartBeatJobControllerService
	
  def index = {
    def methodName = params.operation
    if (!methodName) {
      return [status:"Sending Hearbeats is ${heartBeatJobControllerService.IsRunning()?'ON':'OFF'}"]
    }

    if(heartBeatJobControllerService.respondsTo(methodName)) {
      heartBeatJobControllerService.invokeMethod(methodName, null)
      return [status:"Sending HeartBeats has been ${methodName}d"]
    } else {
      return [status:"${methodName} Operation Not Available"]
    }
  }
}

So, now the controller is closed for modification...if new operations get introduced on the HeartBeatJobControllerService, I don't have to touch HeartBeatJobController. For example, if start() and shutdown() operations come to being, then its just the matter of implementing them in the HeartBeatJobControllerService and I am done. Again, not every case turns out to be as simple as this, but I look for opportunities to knock out duplicate code wherever feasible.

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [0]

XP Days Indore 2010

Yesterday, I finished my sessions at the XP Days, Indore...organized by ASCI (http://www.agileindia.org/xpdaysindore2010/xp-days-indore-2010-program) on OO Design Principles and Driving OO Design using Tests at XP Days Indore. It was fun to interact with the students at the university!

I started with a small Math Game for kids to help them identify numbers....having about 5 story cards, with some one who had already implemented the first story (existing code as starting point). Goal was to evolve Object Design using tests...make mistakes on the way, apply OO principles, refactor the design and deliver the story; eventually learn design guidelines and good practices. Each story progressively builds upon the previous...the goal is not to complete the exercise, but to show how to do evolutionary design using tests as specifications for the software being produced.

Here is the Problem:

Here are the Slides:

Here is the code to start design:
package org.agileindia.mathworks;

import java.util.Arrays;
import java.util.List;

import org.junit.Test;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.*;

public class FilterSpecs {
	
	@Test
	public void itSelectsPrimeNumbers() {
		//Given
		List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
		
		//When
		List<Integer> primeNumbers = Filter.selectPrime(numbers);
		
		//Then
		assertThat(primeNumbers, hasSize(2));
		assertThat(primeNumbers, hasItems(2, 3));
		assertThat(primeNumbers, not(hasItems(1, 4)));
	}
	
	@Test
	public void itDoesNotSelectNegativePrimeNumbers() {
		//Given
		List<Integer> numbers = Arrays.asList(-1, 2, -3, 4);
		
		//When
		List<Integer> primeNumbers = Filter.selectPrime(numbers);
		
		//Then
		assertThat(primeNumbers, hasSize(1));
		assertThat(primeNumbers, hasItem(2));
		assertThat(primeNumbers, not(hasItems(-1, -3, 4)));
	}

}
package org.agileindia.mathworks;

public class Filter {

	public static List<Integer> selectPrime(List<Integer> numbers) {
		List<Integer> primeNumbers = new ArrayList<Integer>();
		for (Integer number : numbers) {
			if (isPrime(number)) {
				primeNumbers.add(number);
			}
		}
		return primeNumbers;
	}
	
	private static boolean isPrime(int number) {
        if (number < 2) {
        	return false;
        }
        for (long i = 2; i*i <= number; i++) {
            if (number % i == 0) {
                return false;
            }
        }
        return true;
	}
}

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [6]

Analysis (Code Coverage, Design Metrics) on Groovy Code

On my other project in Groovy, I finished integrating Cobertura Code Coverage and JDepend for Design Metrics. This post builds up on my earlier post Streamline build scripts creation with Gant and ConfigSlurper. Essentially, I have two reports directories xml and html, underneath them are folders containing Coverage, Design Metrics and Test reports. Below is my project structure:

Below is the sample Gant file that shows how to do this. It defines folders related to Code Coverage output, defines baselines for line coverage (81%) and branch coverage (68%) as properties (see the Code Coverage Properties section) and so are folders for JDepend output (see the Design Metrics Properties section).

// Properties
final srcDir = 'src/'
final testDir = 'test/'
final libDir = 'lib/'
final buildDir = 'build/'
final classesDir = buildDir + 'classes/'
final reportsDir = buildDir + 'reports/'
final xmlReportsDir = reportsDir + 'xml/'
final htmlReportsDir = reportsDir + 'html/'
final xmlTestReportsDir = xmlReportsDir + 'test/'
final htmlTestReportsDir = htmlReportsDir + 'test/'
final baseFolder = 'com/company/product/'

//Code Coverage Properties
final instrumentedDir = buildDir + 'instrumented/'
final xmlCoverageReportsDir = xmlReportsDir + 'coverage/'
final htmlCoverageReportsDir = htmlReportsDir + 'coverage/'
final coverageDataFile = 'cobertura.ser'
final int lineCoverageBaseline = 81
final int branchCoverageBaseline = 68

//Design Metrics 
final designMetricsFile = ''
final xmlDesignMetricsReportsDir = xmlReportsDir + 'design/'
final htmlDesignMetricsReportsDir = htmlReportsDir + 'design/'

def antProperty = ant.project.properties 
final antHomeDir = antProperty.'ant.home' + '/'
final antLibDir = antHomeDir + 'lib/'

ant.path(id:"libs") {
	fileset(dir:libDir, includes:"**/*.jar")
}

ant.path(id:"source.path") {
	fileset(dir:srcDir, includes:"**/*.groovy")
}

ant.path(id:"behaviors") {
	fileset(dir:testDir, includes:"**/*.story")
	fileset(dir:testDir, includes:"**/*.specification")
}

ant.path(id:"compile.class.path") {
	path(refid:"libs")
	path(location:classesDir)
}

ant.path(id:"ant.class.path") {
	fileset(dir:"${antLibDir}", includes: "**/*.jar")
}

ant.path(id:"cobertura.class.path") {
	fileset(dir:"${libDir}", includes: "cobertura.jar, **/*.jar")
}

ant.path(id:"instrumented.class.path") {
	path(refid:"libs")
	path(location:instrumentedDir)
}

ant.taskdef(classpathref:"cobertura.class.path", resource:"tasks.properties")

ant.taskdef(name:"jdepend", classname:"org.apache.tools.ant.taskdefs.optional.jdepend.JDependTask") {
	classpath() {
		path(location:antLibDir + "ant-jdepend.jar")
		path(location:libDir + "jdepend-2.9.1.jar")
	}
}

ant.taskdef(name:"easyb", classname:"org.easyb.ant.BehaviorRunnerTask") {
	classpath() {
		path(location:libDir + "easyb-0.9.6.jar")
	}
}

def easyb(testDir, htmlTestReportsDir, xmlTestReportsDir) {
	ant.easyb(failureProperty:"easyb.failed") {
		classpath() {
		    //Do not change the order, else you will get 0% coverage
			path(refid:"instrumented.class.path")
			path(refid:"compile.class.path")
		}
		behaviors(dir:testDir, includes:"**/*.specification, **/*.story")
		report(location:xmlTestReportsDir + "testReport.xml", format:'xml')
		report(location:htmlTestReportsDir + "testReport.html", format:'html')
	}
	ant.fail(message:"OOooo my my...Stopped the build as Behaviors Failed To Run As Expected", if:"easyb.failed")
}

target ("run-test" : 'Run all Easyb Stories and Specifications') {
	depends("compile-source")
	depends("instrument-coverage")
	
	easyb(testDir, htmlTestReportsDir, xmlTestReportsDir)
	
    "cobertura-report"(format:'html', datafile:coverageDataFile, destdir:htmlCoverageReportsDir, srcdir:srcDir)
    "cobertura-report"(format:'xml',  datafile:coverageDataFile, destdir:xmlCoverageReportsDir, srcdir:srcDir)
    "cobertura-check"(totalbranchrate:branchCoverageBaseline, totallinerate:lineCoverageBaseline)
}


target (metrics: 'Static Analysis') {
	depends("run-test")
	depends("design-metrics")
}

def removeOldInstrumentationData(coverageDataFile, instrumentedDir) {
	ant.delete(file:coverageDataFile)
	ant.delete(dir:instrumentedDir)
}

target ("instrument-coverage" : 'Instruments Cobertura Coverage') {
	removeOldInstrumentationData(coverageDataFile, instrumentedDir)
	"cobertura-instrument"(todir:instrumentedDir) {
		ignore(regex:"org.apache.*, org.easyb.*")
		fileset(dir:classesDir, includes:'**/*.class', excludes:'**/*Test.class')
	}
}

target ("design-metrics" : 'Generate Design Quality Metrics') {
  ant.jdepend(format:'xml', outputfile:xmlDesignMetricsReportsDir + 'jdepend.xml') {
      classespath() {
        pathelement(location:classesDir)
      }
      classpath() {
      	path(refid:"compile.class.path")
      }
      exclude(name:"java.*")
      exclude(name:"org.*")
      exclude(name:"groovy.*")
  }

  ant.xslt(basedir:xmlDesignMetricsReportsDir, destdir:htmlDesignMetricsReportsDir, includes:'jdepend.xml', style: antHomeDir + '/etc/jdepend.xsl') {
  	  classpath() {
      	   path(refid:"ant.class.path")
      }
  }
}

target (clean: 'Clean') {
	removeOldInstrumentationData(coverageDataFile, instrumentedDir)
	ant.delete(dir:buildDir)
}

Additionally, I did not want the developers to create a .ant/lib folders in their home directory and throw in jdepend-2.9.1.jar (as gant reads gant-starter.conf and loads user specific libraries that are Ant specific), instead, leaning in favor of making the build self-contained, without the above chores, I chose to use the lib folder for all the libraries...

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [0]

Brevity with Groovy's groupBy

Lets say you have a Row with number and a tag. Tag is used to annotate rows with rules and a unique tag Id. More than one row can have the same tag and hence tag Id. The two abstractions are represented as
public final class Row extends LinkedList {
    final int number
    Tag tag
}
Here is the Tag class
public class Tag {
    String id
    private final rules = [] as Set
}
Here is the Easyb scenario that groups the rows by tag Id.
scenario "groups by tags and publishes them in the result", {
	given "that I have tagged rows", {
		row1 = new Row(1, [id:'tag2', rule:'Rule 1'] as Tag, ["348", "dalald"])
		row2 = new Row(3, [id:'tag1', rule:'Rule 2'] as Tag, ["345", "tomty"])
		row3 = new Row(2, [id:'tag2', rule:'Rule 1'] as Tag, ["348", "dhaval"])
		row4 = new Row(4, [id:'tag1', rule:'Rule 2'] as Tag, ["345", "tyber"])
		rows = [row1, row2, row3, row4]
	}
	when "I group the rows by tag id", {
		rowsByTag = groupByTag(rows)
	}
	then "I should see rows that are grouped by tag id", {
		rowsByTag.size().shouldBe 2
		ensure(rowsByTag['tag2'].flatten()) {
			contains(["348", "dalald", "348", "dhaval"])
		}
		ensure(rowsByTag['tag1'].flatten()) {
			contains(["345", "tomty", "345", "tyber"])
		}
	}
}
Initially I had written the code for groupByTag() like this
//Client code
def rowsByTags = groupByTag(rows)
rowsByTags.each { tag, row ->
   // Do something with each tag and row
}


def groupByTag(rows) {
    def taggedMap = [:]
    rows.each { row ->
        def taggedRows = [] 
        if (taggedMap[row.tag.id]) {
            taggedRows = taggedMap[row.tag.id]
        } 
        taggedRows << row
        taggedMap.put(row.tag.id, taggedRows)
    }
    taggedMap
}
But, I while reading Venkat Subramaniam's Programming Groovy I came across this groupBy(Closure closure) method for collections and here is the refactored groupByTag():
def groupByTag(rows) {
    rows.groupBy { row ->
        row.tag.id
    }
}
Indeed beauty in brevity!

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [0]