About Me

My photo
Related, I keep most of my code here https://github.com/rdammkoehler

Wednesday, December 1, 2010

Guice, Guice Servlet, Jersey, and the Request Scoped Dependancy

On my current project I've been working with Matt Foy to improve the tests around a rather large application. The original developers chose to use Guice with Guice Servlet and Jersey services to create their application. One of the things that we ran into this week was that we had no tests around the Guice configuration. So while everything seemed OK on the CI server, as soon as we actually deployed the application we discovered that the Jersey servlets would not function because various Request Scoped dependancies had not actually been injected. Basically our Module configurations were a mess and we didn't know it.

So, we created a simple sandbox representation of this problem and then discovered a way to effectively test that the Guice configuration was correct. We must give credit to the authors of Guice for making their test available, this is how we figured it out.

First let us show you the classes that I want to test, note this is highly contrived for the purpose of clarity;

The following servlet is simply in place to allow us to have a servlet with a Request Scoped dependency in a Jersey service.

The Dependancy is simply an implementation of an interface, neither of which contain any methods;

And we have a custom module for creating the Dependency. Note that the Dependancy.class is scoped as @RequestScoped;

And finally, the GuiceServletContextListener that would be used by the Servlet container to do the actual injections at runtime;

Now that you have the context, here's how we solved the problem. The GuiceFilter used by Guice Servlet support conducts the injection activity for the servlet when a request is executed. If you attempt to get, from the injector, any injected instance that is RequestScoped you will get an exception from the Injector indicating that you've requested a resource outside the scope of a Request. It's your own fault really :-).

So, by contriving a filter chain of assertions you can determine if Guice has actually injected the dependencies correctly. Here's how;

First we created this Assertion class;

The assertProvisioningType method allows you to assert that an instance is provided for any type request and that the provided instance is of the appropriate type.

The assertInstantiablity method allows you to assert that an instance is provided for a requested type.

The applyFilterChainAssertion method executes the given FilterChain using the GuiceFilter as the head of the chain. JMock is used in this case to support our current project configuration (Note: We'll be rewriting this with Mockito soon enough.) When you call this method with a FilterChain full of assertions they will have access to the Injector and will be within the Request scope, so you can easily make assertions about them without getting the nasty exception pictured here;

The expose method allows you to directly fetch a Request Scoped instance from the injector for additional testing.

Here is the test suite from our contrived example;

Hope this helps someone.


Sunday, December 27, 2009

An interesting discovery today. I upg...

An interesting discovery today. I upgraded my development environment to Eclipse Galileo/Cocoa-64 yesterday. This caused a class-path issue that was unexpected. As it turns out Galileo packages Junit 4.5, and Junit 4.5 uses a signed version of hamcrest. This conflicts with JMock 2.2.0's hamcrest libraries and causes my tests where mocks are used to break with a java security exception. It looks sort of like this;

java.lang.SecurityException: class "org.hamcrest.TypeSafeMatcher"'s signer information does not match signer information of other classes in the same package
at java.lang.ClassLoader.checkCerts(ClassLoader.java:851)
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:566)
at java.lang.ClassLoader.defineClass(ClassLoader.java:692)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)

So, the first thing I did was update JMock to the newest version thinking this was simply an issue with JDK versions or something. That didn't work, but it's helpful to have the 'latest and greatest' I guess, so no harm done. 
After some quick googling about I discovered the issue was multiple hamcrest libraries and simply changed my class-path order to place Junit at the end of the classpath (after JMock) and voila, problem solved.

So, if your moving to Galileo and your tests with mocks suddenly start breaking, the simple fix is to make sure JUnit follows JMock (and it's version of hamcrest) in your classpath.


Friday, January 23, 2009

Dumbness!

The economy goes to pot and suddenly Google Docs can't publish to my blog without hosing my formatting. My apologize to anyone who just got blasted with 12 consecutive updates about a new post on this Blog. I was trying to fix the formatting errors that Google-Docs shoved out there.


Check-Style is Mental Retardation

<vent>

So I've been working on and off with a development team that uses Checkstyle as part of their ANT builds for projects. The check style rules contain all sorts of arcane rules about code style. Just to give you a taste, the following does not pass muster with this rule set;


1: package format.test;
2:
3: import java.lang.*;
4: import format.util.*;
5:
6: abstract public class CheckstyleHatesThisClass {
7:     public final static String regex = "\\(.*";
8:     public final String terminal = ConstantInjector.fetch("hate.terminal");
9:
10:    abstract public String getDataString();
11:
12:    final public String return_parenthetic_part() {
13:        final String target = getDataString();
14:        if ( target.matches(regex) ) {
15:            return SlicerDicer.extract(regex,terminal,target);
16:        } else {
17:            return "";
18:        }
19:    }
20: }

Begets the following list of complaints from check style;

  • line="3" severity="error" message="Using the '.*' form of import should be avoided - java.lang.*." 

  • line="3" column="1" severity="error" message="Redundant import from the java.lang package - java.lang.*." 

  • line="4" severity="error" message="Using the '.*' form of import should be avoided - format.util.*." 

  • line="6" column="10" severity="error" message="'public' modifier out of order with the JLS suggestions." 

  • line="7" column="18" severity="error" message="'static' modifier out of order with the JLS suggestions." 

  • line="7" column="32" severity="error" message="Name 'regex' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'." 

  • line="10" column="14" severity="error" message="'public' modifier out of order with the JLS suggestions." 

  • line="12" column="11" severity="error" message="'public' modifier out of order with the JLS suggestions." 

  • line="12" column="25" severity="error" message="Name 'return_parenthetic_part' must match pattern '^[a-z][a-zA-Z0-9]*_?[a-zA-Z0-9]*$'."

  • line="13" column="22" severity="error" message="Name 'target' must match pattern '^([A-Z0-9]*_?)*$'." 

  • line="14" column="18" severity="error" message="'(' is followed by whitespace."

  • line="14" column="40" severity="error" message="')' is preceded with whitespace."

  • line="15" column="51" severity="error" message="',' is not followed by whitespace."

  • line="15" column="60" severity="error" message="',' is not followed by whitespace."

  • line="16" column="14" severity="error" message="'}' should be alone on a line."


Now I get that people like to have it 'their way' and can be particular about coding standards, but this is just nuts. I'm not a fan of 'import blah.*', but should that be an error? Or how about white-space between the opening parenthesis and the expression in an if statement, I'm mean come-on people. THis is just stilly. 

I'll give you, I combine all the faux pas I could recall to make my example. But it has not been uncommon for me to do a build and then spend upwards of an hour tracking down and correcting these 'check-style errors'. 

Now, before someone goes off an gets all snippety with me about 'coding standards are important', I don't disagree with that. I think code should be formatted in a readable manner that is acceptable to any casual reader. If it has a few peculiarities, that's OK too. But here is where the retardation comes in, check-style is reactively telling me that I'm doing something 'wrong' when in fact I'm doing something that, while obnoxious, isn't actually 'wrong'. There is a grey area here. 

Wrong would be doesn't compile. Wrong would be it's unreadable. Wrong would be offensive or inappropriate. 

Wrong is not visually unappealing. Wrong is not something other than I would have done.

There is no defensible case for these kinds of rules. None what-so-ever. I know, I've tried to make the case.

Here's a great idea, everyone go get a code formatter, or use the one installed in your IDE. And format the code BEFORE you compile it, without complaint, and be done with it. [Did you know that Eclipse can run the formatted every time you save a file, automagically!]

The pragmatic thing is, does the code do what it's supposed to do? Does it solve the businesses problem? It's totally irrelevant if some dried up bean counting sycophant wants to appease the 'code format gods' with some set of archaic rules about where curly braces go. We can make that appeasement, but lets do it with a proactive solution. 

Anyway, this has been making me nuts and wasting a lot of my time for two months. The only upside is, I get paid to make the corrections. But I feel dirty, wrong, and used making these kinds of fixes; as if I'm not a the jock I like to think I am because I can't un-train myself from years of putting a close curly before the word else or not capitalizing final variables inside a method.

<vent/>


Saturday, May 3, 2008

Granularity Optimization

[I've been working on this entry for quite a while, I've just finally decided to publish it.]

When planning a project it is critically important to find an optimal task size. There are several reasons behind this. First and foremost, any estimate is destined too be inaccurate. Additionally, it is impossible to effectively assign more than one resource to a task. Lastly, if tasks are defined to specifically they become brittle and must be remade more frequently. 

With respect to inaccuracy, an estimate made early in a project, when the details are not well understood, or made under pressure to simply publish a schedule is commonly incorrect by as much as 50%, sometimes more. If the project team iteratively re-estimates tasks the accuracy of the estimate might progressively improve as the start-date for the task approaches. However, the nature of estimating tells us that we are simply making the best educated guess we can about the effort required to achieve some goal. None of us are able to predict the future with consistent accuracy and precision. So, if by using an iterative re-estimation technique we can manage a accuracy of +/-10% on our estimate we're doing pretty well. But, if a task is estimated at 30 days (240 hours) and we are wrong by 10% we have at least three things to consider. 

First, if we finish 10% early (27 days) we may create idle time for the person(s) working the task. Idle time can lead to one or more dangerous effects; gold-plating being the most dangerous. As they say, Idle Hands are the Devils Tools. There are also resource utilization considerations, but they are less relevant and, at least in my opinion, irrelevant. 

Second, if we finish 10% late (33 days) we may slip a delivery or otherwise impact future tasks which has a cascading effect on the overall project. This is a more pronounced problem to be sure. I think the consequences should be obvious to the reader.

Third, in either case we over pay for the task in terms of money; for early delivery we pay for idle time (or the Devil's work), for late delivery we pay for the additional work.

In order to make effective assignments of resources ideally we have one task for one worker. This is true in most kinds of work. Those who choose to employ paired programming, for all intents and purposes are using two people in the place of one. Often times large tasks are created and assigned to a team member; e.g. Build sub-system X. But as time passes and sub-system X is not complete, more people may be assigned to do the work; to help. This is not an effective way to bring a task back in line with the schedule. If one team member is in the midst of developing a solution for a task, and suddenly more team members are added to the task, everyone's productivity slows. The original team member must slow down in order to communicate the work he has done, the work that remains, and all the considerations that he may have made to this point. The new team members can't make any progress until all this information has been communicated. Finally, all of the assignees must now communicate with each other about what has been and will be done. 

Worse still, if too many people are assigned to a task you can exceed the maximum partition-ability of the task. Think two workers, one shovel. If an when you exceed the maximum partition-ability of a task, the result is that the 'extra workers' must be idle in order to prevent conflicts. Furthermore, communication about the task must also increase which degrades all worker performance. The next result is that the task takes even longer to complete than originally scheduled.

The final concern about task granularity is over analysis and the creation of too many too detailed tasks. This becomes a problem simply because changes in the design and architecture specifics of a project will cause these tasks to become invalid. They must then be discarded or replaced. If this occurs too frequently the overhead of managing the task list outweighs the advantages of the details. This will impact team performance creating 'start delays' of tasks and also potentially increasing the amount of waste within a project; especially if some of these detailed tasks are taken from a backlog to fill gaps in the utilization of team members. 

Finding the balance between too much detail and not enough is a significant challenge for a project planner; it is one of the distinguishing characteristics of a great planner. Keeping in mind the impact of inaccuracy, the maximum partition-ability of a task,  and the risk of over analysis while planning can help smooth out a task plan while still providing a solid time/effort management mechanism.

Partitionability

Partitionability describes the degree to which something can be functionally decomposed. The partitionability of a process, algorithm, or function is determined by the refinement of a design. The partitionability directly correlates to the number of distinct atomic tasks required to complete the implementation of the process, algorithm, or function.

Partitionability is used when estimating the man-time requirements for implementation. For example, some functionality X requires 22 man-hours to complete. X can be decomposed into 5 distinct component parts (its partitionability is 5). Optimally, X can be completed in 22 / 5 = 4.4 hours by a team of 5 developers. Stated formulaically;


To = Tm / P


Where To = Optimal Time, Tm = Man-Time, and P = Partitionability



Good, Fast, and Cheap. Pick Two

The designer's Holy Triangle or, as I call it, the Magic Triangle. There is another set of considerations beyond the Magic Triangle. Call it a corollary triangle, I call it 'the technology balance'. The idea is that within a technology project there are three considerations; The use or creation of new and innovative technology, getting the job done (or doing business), and correctness (in the academic sense). I'm aware of other considerations but I feel these three are the the most contentious considerations. 

When technology projects start there is often a lot of conversation about what technologies should be applied. Often, teams choose to use newer or more cutting edge technologies in favor of older more stable technologies. Part of this is facination with the new, part of it is a hedge against those things we don't like about the old. All of these are valid and reasonable determining factors for technology selection. 

Another observation is that technology teams, given enough time, will argue endlessly about the correctness of any given solution. There is always debate about what is 'the right thing' in tool selection, pattern application, hardware configuration, design and planning approaches and just about any conceivable facet of the project. 

Always in a project there is a push to deliver the product on-time and within the budget. We've all heard the complaints about schedule driven decisions, right-to-left scheduling, scope creep and defect management; contributors to concern about delivering on-time.

We go round and round these three topics in every project. Depending upon the focus and dicipline of the team and it's leaders we may not complete a project because of one or all of these considerations. By being aware of these contentions and managing our activities in accordance with the balance that must be maintained we can be more successful with our projects.