Monday, May 3, 2010

I hate looping / iterating / eaching

I really hate looping. I mean I really hate looping. Why is that you ask? Because most of the time our looping is not looping. You're filtering, you're transforming or you're calculating, you're not looping. Looping is a means to an end. You loop to perform those actions. But syntactically it's quite common in many languages to see something like: for (blah in blahs) do some filtering / transforming / what ever. Why does the statement "for (blah in blahs)" come first? why isn't it blahs.filter(some predicate) or filter(blahs predicate) or blahs.transform(some stuff) or really so many other options. Why isn't the intent of transforming / filtering / calculating brought to the forefront?

I love clojure's solutions to the issue: filter, map, reduce. You can get rid of 99% of all your looping and describe better what you're trying to do. I've been trying this in java (I know I know it's a mistake)... with google collections. I mean great they have filter, transform, this will look great. It really doesn't:

List filtered = new ArrayList( Collections2.filter(foos, new Predicate() { @Override public boolean apply(Foo foo) { return foo.isBar() && foo.isBaz(); } }));
vs
List filtered = new ArrayList(); for (Foo foo : foos) { if (foo.isBar() && foo.isBaz()) { filtered.add(foo); } }

Well fine I'm maintaining intent (I guess) by using a filter method and a predicate, but the whole filter mechanism gets completely lost in all the boiler plate java cruft. I love that I can just implement an apply method, highlighting the boolean expression, and the magic is done for me, but I need so much more code to get my work done. Sure I'm removing duplication of looping (which is nice) but at such a legibility cost. Maybe I'll get used to all the crazy syntax, and it will just fade into the background, but for the moment I'm really doubting it.

Thursday, April 8, 2010

TDD Starting Points + Roman Numerals Kata

I worked on the roman numerals kata this week with danp, and learned some new things about TDD and approaching a problem. Where you start with TDD and what kind of insights you can draw from a domain before you start really effect your direction. As I'm typing this it seems incredibly obvious, but it was still a good lesson for me to learn.

We started the kata few times and scrapped our code each time as we started realizing our approach wasn't quite what we were looking for. Honestly if I hadn't had a pair, I probably wouldn't have started over so many times, or pushed quite so hard to find a better way to look at the problem.

What did we start with? We started with the tests. Each time we tried the problem, we picked what we thought was the simplest test and then picked what we thought was the next simplest test. What we found was that we were backing ourselves into corners in our implementation because our tests weren't actually very good starting points.

I'm thinking TDD is like a hill climber where you start really matters. In a way that is the challenge TDD presents you with: What is simplest thing to start with?

Saturday, January 30, 2010

Generating EJB3 classes from a database

Generating EJB3 classes from a database is not that hard. Yay! First you need to download and unzip hibernate tools. You'll want to have the hibernate tools docs at hand. Next you need to grab a bunch of jars. Almost all the jars can be found in /plugins/org.hibernate.eclipse.x.x.x/lib/tools/hibernate-tools.jar . Then download ejb3-persistence.jar. Below are all the jars I collected. Don't worry about overkill, you're not going to include any of these jars in your distribution.

antlr-2.7.6.jar dom4j-1.6.1.jar hibernate3.jar jtidy-r8-20060801.jar asm-attrs.jar ehcache-1.2.3.jar jaas.jar log4j-1.2.15.jar asm.jar ejb3-persistence.jar javassist.jar lucene-core-2.2.0.jar bsh-2.0b1.jar freemarker.jar jboss-cache.jar oscache-2.1.jar c3p0-0.9.1.jar hibernate-annotations.jar jboss-common.jar postgresql-8.4-701.jdbc3.jar cglib-2.1.3.jar hibernate-commons-annotations.jar jboss-jmx.jar proxool-0.8.3.jar commons-collections-2.1.1.jar hibernate-entitymanager.jar jboss-system.jar swarmcache-1.0rc2.jar commons-logging-1.0.4.jar hibernate-search.jar jdbc2_0-stdext.jar concurrent-1.3.2.jar hibernate-tools.jar jgroups-2.2.8.jar connector.jar hibernate-validator.jar jta.jar

Now create your build.xml file:

<?xml version="1.0" encoding="UTF-8"?> <project name="my-proj" default="gen_hibernate" basedir="."> <property name="src" location="src" /> <property name="build" location="build" /> <property name="generated" location="generated" /> <path id="toolslib"> <fileset dir="${basedir}"> <include name="lib/*.jar"/> </fileset> </path> <taskdef name="hibernatetool" classname="org.hibernate.tool.ant.HibernateToolTask" classpathref="toolslib" /> <target name="gen_hibernate"> <hibernatetool> <jdbcconfiguration packagename="com.my.proj" configurationfile="hibernate.cfg.xml" detectManytoMany="true" detectOptimisticLock="true"> </jdbcconfiguration> <hbm2hbmxml destdir="${generated}" /> </hibernatetool> </target> <target name="gen_java" depends="gen_hibernate"> <hibernatetool destdir="${src}"> <annotationconfiguration configurationfile="hibernate.cfg.xml"> <fileset dir="${generated}"> <include name="**/*.hbm.xml"/> </fileset> </annotationconfiguration> <hbm2java jdk5="true" ejb3="true"/> </hibernatetool> </target> <target name="compile" depends="gen_java"> <mkdir dir="${build}/classes" /> <javac srcdir="${src}" destdir="${build}/classes" classpathref="toolslib" /> </target> <target name="jar" depends="compile"> <jar destfile="my-proj.jar" basedir="${build}/classes" /> </target> <target name="clean"> <delete dir="${build}" /> <delete dir="${src}" /> <delete dir="${generated}" /> </target> </project>

If you're using postgres your hibernate.cfg.xml file should look like:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory name="myproj"> <property name="hibernate.connection.driver_class">org.postgresql.Driver</property> <property name="hibernate.connection.url">jdbc:postgresql://your-url</property> <property name="hibernate.connection.username">your-username</property> <property name="hibernate.connection.password">your-password</property> <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property> </session-factory> </hibernate-configuration> </pre></blockquote>

run ant jar and you should be good to go!

Depending on how you're setup you should also consider running <hbm2cfgxml ejb3="true"> it creates a nice hibernate.cfg.xml file with all the classes and your DB connection info.

Tuesday, January 19, 2010

Dependency Injection Frameworks - A Rant

Uncle Bob has a great post on dependency injection frameworks. I'm so glad he wrote that article. There is precious little out there (maybe this is the only article) about why the DI frameworks suck and why DI is great. To be clear DI by hand works very well. And if all you need to do is DI, rolling it by hand is just as good as using a framework. In fact it wasn't until recently that I even saw a point to DI frameworks at all.

The only argument about DI frameworks that ever made much sense to me was that DI frameworks are great if you want to run your application with different configurations. But when do you want different configurations? Seriously when? For me, the only time I've wanted different configurations is for testing. Not unit or automated testing, but testing in the sense of I want to run the app and I don't want to hit prod.

But why do you need a framework to do that? Maybe you have a different main method. Or maybe you have a properties file. But if all you need are different configurations, a DI framework is an expensive price to pay.

What are the costs? Besides needing to learn a new framework, the DI frameworks are like a cancer. Once you start using them they invade and don't stop invading. You start @Autowiring and @Inject-ing and soon your whole app is cluttered with that crap. Not to mention the XML configs or Guice modules floating around. Maybe I'm doing it wrong, but why do I even want to invest the time to learn how to do it right? The benefits of using the frameworks seem so slim it's doesn't seem worth my time.

However, I did get convinced recently that using Spring DI was the correct choice for a web app I'm working on. Why? Because when Spring manages your objects it does some magic with transactions and sessions and it's all pretty convenient. I still hate it! And it feels wrong. And I believe you can get the magic without the DI. It's a question of how much do you want to fight against your framework. For my current project the answer was clear, not that much.

The only value I get out of using Spring's DI is the magic it does in the background. Their DI is total crap. If you don't need the magic, it's hard to understand why you need the framework.

Wednesday, October 28, 2009

Abstract Class Smell

PLEASE SEE THE UPDATES BELOW, I didn't realize that my issue was with the Template Method Pattern.
------------------------------------------------------------------------
Original Post:

I coded up a smell today, I had an abstract class who's public methods were calling the abstract implementations. Here's kind of what it looked like:

public abstract class Foo {
  abstract SomeObj foo();
  abstract SomeObj bar();
  public void somethingFooDoes() {
      SomeObj a = foo();
      SomeObj b = bar();
     //do some stuff with a + b
  }
}

How did I get here you might ask. Well, there were going to be two implementations of Foo, a prod implementation and a sandbox implementation. I started off with Foo as an interface and began coding up the Prod + Sandbox impls. It turned out that the prod and sandbox implementations had really similar structures. So, I made Foo an abstract class and moved the common stuff in there. A few more refactorings and Foo ended up looking like it does above. It then dawned on me, Foo was really using different strategies to get at the SomeObjs, I refactored to the strategy pattern:

public class Foo {
  private final SomeObjProducer someObjProducer;
  public Foo(SomeObjProducer someObjProducer) {
     this.someObjProducer = someObjProducer;
  }
  public void somethingFooDoes() {
      SomeObj a = someObjProducer.foo();
      SomeObj b = someObjProducer.bar();
     //do some stuff with a + b
  }
}

Now Foo has become concrete and is configurable with the different strategies for producing SomeObjs. To me this code is much more flexible and it now has collaborators. Where in the Abstract implementation it was kind of collaborating with itself (yuck!)

What's the moral of the story? If you have an abstract class and you find yourself calling abstract methods in your concrete methods (whoa that's a mouthful) consider refactoring to the strategy pattern.

UPDATE: a co-worker correctly pointed out that the first code snippet of Foo was the Template Method Pattern. Maybe it's too broad a statement, but it seems that anytime you have a template method pattern you could refactor it into the strategy pattern. Taking your inheritance based code and refactoring it into composition based code. Context is king, but these days I certainly favor composition over inheritance.

UPDATE AGAIN: I received some good complaints regarding my code sample.

Imagine using the more standard Game example from wikipedia (but simplified for brevity)

public abstract class Game {

 public void playOneGame() {
  while(!endOfGame()) {
   makePlay();
  }
 }

 public abstract boolean endOfGame();
 public abstract void makePlay();
}
This could be refactored to use composition instead of inheritance, where Game is now an interface.
public class GamePlayer {
 private Game game;
 public GamePlayer(Game game) {
  this.game = game;
 }

 public void playOneGame() {
  while(!game.endOfGame()) {
   game.makePlay();
  }
 }
}

Tuesday, October 13, 2009

Hollywood Dilemma

At sdtconf over the weekend I led an open spaces discussion about the Hollywood Principle and testing. Venkat Subramaniam took the time to post a really thoughtful article about it. I'll quote it below, but it is worth reading!

The discussion was around the cost and reason for inverting control, Venkat provided a toy problem which we twisted for our own purposes, we modeled a paper boy. The paper boy requests payment from a customer and the customer can either pay or stiff the paper boy.

I argued for the following:

public class PaperBoy {
  public void collectPayments(List customers) {
    for(Customer customer : customers) {
      customer.getPayment(this, 200);
    }
  }
  //...
And the test
Customer customer = mock(Customer.class);
PaperBoy paperBoy = new PaperBoy();
//set up a payment to be collected;
paperBoy.collectPayments(customer);
verify(customer).getPayment(paperBoy,$$$);
and the Customer
public class Customer {
  public void getPayment(PaperBoy paperBoy, int amount) {
    if (hasNoMoney || doesNotCareToPay)
      paperBoy.stiff(this);
    else {
      deductMoney(amount);
      paperBoy.acceptPayment(this, amount);
    }
  }
  //...
and the Test
Customer customer = new Customer(someMoney and a bad attitude);
PaperBoy paperBoy = mock(PaperBoy.class);
customer.getPayment(paperBoy,$$$);
verify(paperBoy).stiff(customer);
etc. for the other cases. Venkat points out some issues with this kind of implementation that I'd like to address:
Problem 1. The above code has some unnecessary coupling and bi-directional relationship. The Customer depends on PaperBoy. That is a coupling that I would seriously question.

Problem 2. The unit test is now made to do more. It has to create a mock of the PaperBoy. Even if you tell me it is not much code, a single line of code that is not absolutely needed is a lot of code IMHO. You don't have to maintain code that you do not write.

Problem 3. Are you really stiffing the PaperBoy? Who decides that? Can a paperboy decide that under very hard economic conditions, a loyal customer may be deserves a break? I have no problem the customer deciding to pay or not, but if that is stiffing or not is for the paperboy to decide IMO.

I'd like to address problem 3 first. The paper boy can still cut the guy a break, he just does it in his stiff method. Or maybe it shouldn't be a stiff method, maybe it should be an iWontPayMethod().

Problem 1. I really don't like the coupling! The coupling would be limited if the Customer was talking to a debt collector interface, and the PaperBoy was talking to a Payee(uhg) interface. But it's still a little smelly. I don't fundamentally see a problem with the bi-directional relationship, but maybe that's just because I haven't coded too much with bi-directional relationships (and maybe there's a good reason for that).

Problem 2. Let's take a look at Venkat's code + what some tests would look like.

public class PaperBoy {
  public void collectPayments(List customers) {
    for(Customer customer : customers) {
      int payment = customer.getPayment(200);
      if (payment > 0)
        acceptPayment(customer, payment);
      else
        stiff(customer);
    }
  }
  //...

public class Customer
{
  public int getPayment(int amount) {
    if (hasNoMoney || doesNotCareToPay)
      return 0;
    else {
      deductMoney(amount);
      return amount;
    }
  }
  //...
The Customer Tests:
Customer customer = new Customer(someMoney and a bad attitude);
assertEquals(0,customer.getPayment($$$);
So Venkat is correct in this example the mocks add 2 extra lines per test which isn't great. But that's not the whole story. Let's take a look at the PaperBoy tests.
Customer customer = new Customer(someMoney and a bad attitude);
PaperBoy paperBoy = new PaperBoy();
//set up a payment to be collected, let's assume this is one line
paperBoy.collectPayments(customer);
assertTrue(paperBoy.wasStiffedBy(customer);

Customer customer = new Customer(someMoney and a good attitude);
PaperBoy paperBoy = new PaperBoy();
//set up a payment to be collected, let's assume this is one line
paperBoy.collectPayments(customer);
assertTrue(paperBoy.collectedPaymentFrom(customer, $$$);
I have two issues with the PaperBoy tests:
  1. There is an extra test needed, which in terms of maintence is not such a good thing.
  2. The PaperBoy tests are highly coupled to the implementation of the Customer. This means anytime you change some behavior of the Customer you might have to change your PaperBoy test, not such a big problem for the 2 tests, but if there are 50? if there are 100? that can be bad news.

It's not clear to me that inverting the control is the "right" thing to do, but I think if you're careful (and you want 100% unit test coverage), inverting the control and using mocks can help you cut down on test complexity and test maintenance, so... mock-on?

Thanks everyone who participated in the discussions!

Tuesday, September 22, 2009

Contract Tests

I had a post almost a year ago Hard Contracts vs Soft Contracts that was I reminded of when I came across this post on Testing with generic abstract classes. At our company we've been using the abstract test case pattern for a while, but have been struggling with naming... why not just call it FooAbstractTest you ask? Because, well, our build looks for classes that are named Foo*Test* in our test package and tries to run the abstract test cases and it breaks our build. So like any good software engineer instead of solving the problem, we just tried to work around it (sigh).

Anyway, we were struggling for a good naming convention, the best we could come up with was FooBase (terrible) but then as I mentioned I came across Mark's post, which in turn lead me to this wonderful page on c2 http://c2.com/cgi-bin/wiki?AbstractTestCases. The first line says it all, "Contract Tests" and really I knew it all along. I had been thinking of them in terms of hard contracts vs. soft contracts. So now I can feel good about myself and continue being a good software engineer, I have a better name, FooContract.

UPDATE - If you followed the link to the c2 page, you'll see that J. B. Rainsberger is referenced all over the place. Well he just republished his initial thoughts on the Contract Test. Also, if it wasn't clear, I was being very tongue in cheek about not fixing our build, we should do it, but finding a good name for these kinds of tests is also important.

 
Web Statistics