Archive for January, 2010

Trend Lines

It seems we’re in a trend shift that’s deeper than has been experienced in the last several years. I don’t have any empirical evidence for this, but it’s the general direction people seem to be taking when I talk to them. Perhaps it’s a “something different” syndrome and most of these new technologies will never gain any mainstream traction. For my purposes, I’m dissatisfied with my current stack and actively looking to make some changes. Is anyone else feeling the need for a context switch to something different? What other products are likely to get dumped and become just a found memory?

From:
Towards:
Java
Scala, Groovy, Clojure
Object-oriented
Functional/Object hybrid
Spring
Standards based JSR 299 and JSR 330
SQL
Object DBs/NoSQL
Subversion
Git
SOAP
REST
XML
Anything else (Annotations, Wicket, GWT, JSON, Thrift, Protobuf)
Flash
HTML 5

Stomping grapes with Groovy

One of the best new features of Groovy is Grape. It allows a script to connect to Ivy or Maven style repositories and download the dependencies it needs. This lets you bang out a quick script, ship it to another computer, and run it there without having to fiddle around with classpaths, jars, or any other sort of file. I put together a simple demo that shows some of this. The script grabs my RSS feed using ROME and then splits out words longer than 3 characters if they show up more than once. The important part is at the top, however. You can see that I use the Grab annotation to get ROME and Apache Commons Lang. I’m then free to import the classes I need from those jars. Further down, I use an inline Grab to get the Google Collections jar and then create the class I want with a fully qualified name. Pretty cool, I think. You can try it yourself by cutting and pasting this example. You’ll need access to Groovy from your command line or IDE.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/env groovy
@Grab(group='rome', module='rome', version='0.9') //Long-style grab
@Grab('commons-lang:commons-lang:2.4') // Gradle-style grab
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;

class GrapeTest {
  public static final int MIN_WORD_LEN = 4;
 
  static main(args) {
    //Inline grab using fully qualified name (no import statement)
    @Grab('com.google.collections:google-collections:1.0')
    def words = new com.google.common.collect.TreeMultiset()
   
    def feed = getFeed('http://codegoop.com/feed/')
    getCleanFeedLines(feed).each { line ->
      line.split(' ').each { word ->
        if (validWord(word)) {
          words.add(word)
        }
      }
    }
    printResult(words)
  }
 
  def static getFeed(url) {
    def input = new SyndFeedInput()
    return input.build(new XmlReader(new URL(url)))
  }
 
  def static getCleanFeedLines(feed) {
    def lines = new ArrayList()
    feed.entries.each { entry ->
      entry.contents.each { content ->
        cleanLine(content.value).each { line ->
          lines.add(line)
        }
      }
    }
    return lines
  }
 
  def static validWord(word) {
    return StringUtils.isNotBlank(word) && word.size() >= MIN_WORD_LEN;
  }
 
  def static printResult(result) {
    result.elementSet().each {
      if (result.count(it) > 1) {
        println it + " found " + result.count(it) + " times"
      }
    }
  }
 
  //Only use the code in the <p> blocks
  //Remove html tags and non-alpha (leaving space)
  def static cleanLine(str) {
    def cleanedLines = new ArrayList()
    def subLines = StringUtils.substringsBetween(str, "<p>", "</p>")
    subLines.each { subLine ->
      def line = StringEscapeUtils.unescapeHtml(subLine)
      line = line.replaceAll("<(.*?)*>", "").replaceAll("[^a-zA-Z\\s]", "")
                          .toLowerCase()
      cleanedLines.add(line)
    }
    return cleanedLines
  }
}

Running the script gives you something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ ./GrapeTest.groovy (Unix or Cygwin) vs C:\>groovy GrapeTest.groovy (Windows)

about found 6 times
arent found 2 times
around found 2 times
automatic found 2 times
basically found 2 times
been found 6 times
better found 3 times
bring found 2 times
<snip>
  several more lines
</snip>
work found 2 times
write found 2 times
written found 3 times
year found 5 times
youre found 5 times

Now, that’s all great, if the libraries you need are in the default repositories, but what if they aren’t? Well, you can either edit ~/.groovy/grapeConfig.xml and add in the repo you want or, even better, use @GrabResolver(name=’myRepoName’, root=’myRepoUrl’) at the top of your script to retain that “copy/paste” the file feature that seems so nice. GrabResolver is new in Groovy 1.7. See the release notes here

Java EE 6 Automatic Timer

I’ve been playing around with scheduled jobs a bit. I’ve mostly used Quartz in the past, but I thought I’d try out Automatic Timers from Java EE 6. They are pretty simple and can be defined either in an annotation or the ejb-jar.xml file. For instance, I might want to run two different jobs; one every 5 seconds and one every 10 with something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.Date;
import javax.ejb.Schedule;
import javax.ejb.Singleton;

@Singleton
public class SimpleJobs {

  @Schedule(second="*/5", minute="*", hour="*", persistent=true, info="job #1")
  public void jobOne() {
    System.out.println("Job one fired on " + new Date());
  }

  @Schedule(second="*/10", minute="*", hour="*")
  public void jobTwo() {
    System.out.println("Job two fired on " + new Date());
  }
}

The second, minute, and hour values all default to 0, so you need to provide wild cards for them in this case. The “*/5″ and “*/10″ basically means for every interval of X seconds, fire the job. Of course, there are values for day, week, month and year. There is support for ranges and starting time, so you can get as complicated or simple as you need. The persistent element is true by default and tells the server if the timer should remain after a restart or not. The info tag gives a simple name for programmatic display purposes.

I think these automatic timers seem like a nice addition and could come in handy in certain spots. I’m curious about their reliability, mutability, and accessibility though as I haven’t gotten a chance to play with them much. How will jobs react in a cluster or during a server crash? Is there an easy api interface to edit a running schedule? How can I know when jobs are being fired and when they aren’t? I’m going to write some more code and play with them a bit. I need to consolidate the status of all my scheduled jobs into one place, so we’ll see how these fit in. I’m sure a bit of magic pixie dust is all I’ll need.

The tech interview “test”

Have you ever gone on a job interview and had a written technical “test” such as the following?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1.) What is the result of compiling and running the following?
    Select the one correct answer.

public class badTest {
  public static void main(String args[]) {
    int i, j;
    int k = 0;
    j = 2;
    for (i = 0; i <= 9; ++i) {
      j = i + 2;
    }
    k = j = i;
    System.out.println(k);   
 }
}

A. The program does not compile as k is being read before being initialized.
B. The program does not compile because of the statement k = j = i;
C. The program compiles and runs printing 0.
D. The program compiles and runs printing 1.
E. The program compiles and runs printing 10.
F. The program compiles and runs printing 11.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2.)  What happens when the following program is compiled and run?

public class lameTest {
  int i = 0;
  public static void main(String args[]) {
     int i = 1; change_i(i); System.out.println(i);
  }
  public static void change_i(int i) {
     i = 2; i *= 2; new lameTest().change_I_TOO(i);
  }
  protected void change_I_TOO(long i) {
    short j = 100; do {
      i = j / i + 3; j = (short) i;
    } while (j > 22);
  }
}

A. The program does not compile.
B. The program prints 0.
C. The program prints 1.
D. The program prints 2.
E. An exception is thrown.
1
2
3
4
5
6
7
8
9
10
11
12
3.) In the following code, select all the lines that will not compile.

public final abstract class terribleTest {
  public void main(final String args[]) {
    char p;
    int i;
    p = "B";   
    i = p;   
    p = i + 1; 
    p++;
  }
}

If so, did you you get an offer? Did you take it? Perhaps you’re a hiring manager and you’ve given a test like this before. Maybe you still do. If so, why? It’s been my experience that anytime someone asks you to take a written exam such as this, you should turn around and run away, fast! There are so many problems with a test such as this, it’s hard to know where to begin. First, look at the quality of the code. Do you write code like that? Do you want to? What if you got in the shop and all the code was similar to this? Second, who writes code without an IDE? Who cares if the code, as written on paper, compiles or not? Developers have a hard enough time keeping variables, tasks, and trains of thought clear in their head. They don’t need the extra burden of trying to keep track of every little syntax error. That’s why we have tools like modern IDEs and code analysis. Third, does this even count as programming? What problem does it solve? What is the test giver trying to learn? Does it help them determine who is going to be a good candidate and who isn’t? Not in my judgment.

I’ve had the unfortunate experience of taking a test like this on two difference occasions. The first time, I suffered through and did the best I could. I wasn’t offered a job and now know I was better off for it. The second time, I didn’t take the test. Instead, I spoke to the interviewer about my reservations, why he felt the need to use this type of test, and what he was hoping to gain. It turns out, he wasn’t a Java developer and he’d had the outgoing Java dev create the test in order to judge if a person knew software development or not. Whatever the case, this is decidedly not software development. At least not any that I’d want to be a part of.

So, if you’re ever asked to take a test such as this, thank the interviewer for the huge favor they have done you. They told you exactly what it’s like to work for them. It would likely involve scary code, lack of proper development tools, and the pain of cleaning up someone’s mess. If you’re thinking about giving a test like this, please think again. Consider better ways you might use to determine if someone has the qualities you’re looking for. Talk about some of the problems you’re having. Show them some of your code. Have them bring in some of their code. Discuss what makes it good or how it could be improved. Whatever you do, don’t try to figure out if they are a good fit based on something that is so far removed from what a development job is really all about. Trust me. Future interviewees will thank you and you’ll be rewarded with better hires.

Google collections 1.0 released

Google Collections just released version 1.0 final, so now everyone can upgrade and be confident the interfaces aren’t going to change.  I’ve been using the project for awhile now.  It’s really popular, but I’ve been in a couple of shops that haven’t been using it for whatever reason.  I wrote a couple of very simple examples to just showcase some cool features.  Java 1.5 is required.

Simple creation:

1
2
3
List<Integer> emptyList = Lists.newArrayList();
Set<Integer> emptySet = Sets.newHashSet();
Map<Integer, String> emptyMap = Maps.newHashMap();

Immutables:

1
2
3
4
5
6
7
8
9
10
11
List<String> list = ImmutableList.of("One", "Two", "Three", "Four");
Set<String> set = ImmutableSet.of("One", "One", "Two", "Three");
Map<Integer, String> map = ImmutableMap.of(1, "One", 2, "Two", 3, "Three");

//list.add("fail");   // throws java.lang.UnsupportedOperationException
//set.add("fail");    // throws java.lang.UnsupportedOperationException
//map.put(1, "fail"); // throws java.lang.UnsupportedOperationException

System.out.println(list);
System.out.println(set);
System.out.println(map);

prints:

1
2
3
[One, Two, Three, Four]
[One, Two, Three]
{1=One, 2=Two, 3=Three}

Multis:

1
2
3
4
5
6
7
8
9
10
11
Multiset<String> multiset = HashMultiset.create(Arrays.asList("One", "One", "One",
"Two", "Two", "Three"));
Multimap<String, String> multimap = HashMultimap.create();
multimap.put("1", "One");
multimap.put("1", "ONE");
multimap.put("1", "oNe");
multimap.put("2", "two");
multimap.put("2", "t-w-o");

System.out.println(multiset);
System.out.println(multimap);

prints:

1
2
[Three, Two x 2, One x 3]
{2=[two, t-w-o], 1=[oNe, ONE, One]}

Bidirectional map. Changes to one side affect the other.

1
2
3
4
5
6
7
BiMap<String, String> bimap = HashBiMap.create();
bimap.put("ORCL", "Oracle");
bimap.put("RHT", "Red Hat");
bimap.put("VMW", "VMware");

System.out.println(bimap);
System.out.println(bimap.inverse());

prints:

1
2
{VMW=VMware, RHT=Red Hat, ORCL=Oracle}
{Red Hat=RHT, VMware=VMW, Oracle=ORCL}

MapJoiner

1
2
3
MapJoiner mapJoiner = Joiner.on(", ").withKeyValueSeparator(
"'s stock symbol is ");
System.out.println(mapJoiner.join(bimap.inverse()));

prints:

1
Red Hat's stock symbol is RHT, VMware's stock symbol is VMW, Oracle's stock symbol is ORCL

ConcurrentMap with values that expire.

1
2
3
4
5
6
7
8
ConcurrentMap<Integer, String> concurrentmap = new MapMaker().expiration(2L,
TimeUnit.SECONDS).makeMap();
concurrentmap.put(1, "One");
concurrentmap.put(2, "Two");

System.out.println("Map size = " + concurrentmap.size());
Thread.sleep(3000);
System.out.println("Map size = " + concurrentmap.size());

prints:

1
2
Map size = 2
Map size = 0

Map difference compares two maps

1
2
3
4
5
6
7
8
9
10
11
Map<Integer, String> mapOne = ImmutableMap.of(100, "1 hundy", 200, "2 hundy", 300,
"3 hundy", 1000, "10 hundy");
Map<Integer, String> mapTwo = ImmutableMap.of(200, "2 hundy", 300, "3 hundy", 400,
"4 hundy", 1000, "1 dime");

MapDifference<Integer, String> diff = Maps.difference(mapOne, mapTwo);

System.out.println("Same key, different element: " + diff.entriesDiffering());
System.out.println("Same key, same element: " + diff.entriesInCommon());
System.out.println("Elements only on left: " + diff.entriesOnlyOnLeft());
System.out.println("Elements only on right: " + diff.entriesOnlyOnRight());

prints:

1
2
3
4
Same key, different element: {1000=(10 hundy, 1 dime)}
Same key, same element: {200=2 hundy, 300=3 hundy}
Elements only on left: {100=1 hundy}
Elements only on right: {400=4 hundy}

a
a

There is a lot more in the package than just these, but this is a good start. I’ll put up a post on some of the other features that you might find useful later.