In response for my recent group accountability and concensus writing, Darrell posted a link to Michael Lopp's (?) excellent blog entry about mandates. In the very end of that blog entry Michael talks about "external mandates", that is, mandates that are handed down from above without the accompanying reasoning for the mandate.
I've seen that so many times.
And none of those managers have made it to my "list". Most of them have made it on that other list, though.
I just watched Robert Scoble interviewing David Anderson, the Agile Management guy. Good stuff. Seen it yet? Right now would be a good time to do so...
Glen Alleman points out a problem he sees the current agile project management community not giving enough attention:
So if the group is accountable how does the group come to a place where decisions stick? This is one of those differences between principle and practice that is missing from the Agile PM discussion to date.
That last sentence is basically a bait for the rest of us agilists to spend some cycles on thinking about the problem. I took the bait.
Now what are the factors that contribute to making a decision stick?
First of all, it is essential for all involved to know the rules--who gets to "vote" and with "how many" votes, who has the power to make a final call, and the decision making process in general. Having a team member left unsure about what his role is in making the decision is the worst thing that could happen from the perspective of having that team member put effort into the decision and therefore committing himself to sticking with that decision.
Another practical technique for improving the decision's chances of sticking is to have all team members first formulate their own position on the subject independently and come up with some arguments for that particular position. Creating this "think time" for everyone is likely to decrease the risk of the loudest voice walking over the others. Similarly, it often helps if the decision is spell out by someone else than the one who suggested the selected alternative (and there should always be alternatives!).
One final aspect that's important to pay attention to--before making the decision--is to discuss the outcome. Yes, we all think of the outcome when evaluating our options but it makes sense to spell these out explicitly. There's a good chance that I've missed an aspect of a particular option's expected outcome and the more useful information I have on my options, the better able I am to make a decision I can commit to.
Also, we must remember that sometimes it makes sense to turn on an earlier decision. The extremes are rarely optimal and that holds also for decision making frequency; intense trashing isn't much better than having an annual decision making day...
Cedric voices his concerns of someone on the TDD mailing list "requiring a shrubbery before using the debugger".
I won't comment on the actual topic beyond stating that, yes, it doesn't make sense to ban the debugger completely but if there's an economical way to avoid a debugging session, of course we should go for that.
Now, the real reason for this blog entry is that Cedric mentioned shrubberies. For all you Monty Python fans out there, have a few minutes of fun with these.
Markus mentioned something about him needing a method that compares two objects' getter method return values via reflection. I decided to hack together a basic implementation of an abstract JUnit TestCase:
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import junit.framework.TestCase;
public abstract class ReflectionTestCase extends TestCase {
protected void assertBeansAreEqual(Object bean1, Object bean2) {
Method[] methods1 = sort(getters(bean1.getClass().getMethods()));
Method[] methods2 = sort(getters(bean2.getClass().getMethods()));
assertMutualContainment(methods1, methods2);
assertGettersReturnSameValues(bean1, methods1, bean2, methods2);
}
protected Method[] sort(Method[] methods) {
Arrays.sort(methods, new Comparator() {
public int compare(Object o1, Object o2) {
Method m1 = (Method) o1;
Method m2 = (Method) o2;
return m1.getName().compareTo(m2.getName());
}
});
return methods;
}
protected void assertGettersReturnSameValues(Object bean1,
Method[] methods1, Object bean2, Method[] methods2) {
for (int i = 0; i < methods1.length; i++) {
try {
Object value1 = methods1[i].invoke(bean1, null);
Object value2 = methods2[i].invoke(bean2, null);
assertEquals("Method " + methods1[i].getName() + " on " + bean1
+ " doesn't return the same as method "
+ methods2[i].getName() + " on " + bean2, value1,
value2);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
protected Method[] getters(Method[] methods) {
List getters = new ArrayList();
for (int i = 0; i < methods.length; i++) {
if (takesParameters(methods[i])) {
continue;
}
if (methods[i].getName().equals("getClass")) {
continue;
}
if (methods[i].getName().matches("(get[A-Z]).*")) {
getters.add(methods[i]);
}
}
return (Method[]) getters.toArray(new Method[getters.size()]);
}
private boolean takesParameters(Method method) {
return method.getParameterTypes().length > 0;
}
protected void assertMutualContainment(Method[] array1, Method[] array2) {
for (int i = 0; i < array1.length; i++) {
assertContains(array1[i], array2);
}
for (int i = 0; i < array2.length; i++) {
assertContains(array2[i], array1);
}
}
protected void assertContains(Method needle, Method[] haystack) {
for (int i = 0; i < haystack.length; i++) {
if (haystack[i].getName().equals(needle.getName())) {
return;
}
}
fail(toString(haystack) + " doesn't contain " + needle);
}
protected String toString(Object[] array) {
StringBuffer s = new StringBuffer();
s.append("[");
for (int i = 0; i < array.length; i++) {
if (i > 0) {
s.append(", ");
}
s.append(array[i]);
}
s.append("]");
return s.toString();
}
}
...and of course I've got a TestCase for testing the TestCase:
import java.lang.reflect.Method;
import junit.framework.AssertionFailedError;
public class TestReflectionTestCaseAndGetters extends ReflectionTestCase {
private FirstBean bean1;
private FirstBean bean2;
private SecondBean bean3;
private ThirdBean bean4;
private static class FirstBean {
private String stringField;
private int primitiveField;
public int getPrimitiveField() {
return primitiveField;
}
public void setPrimitiveField(int value) {
this.primitiveField = value;
}
public String getStringField() {
return stringField;
}
public void setStringField(String value) {
this.stringField = value;
}
}
private static class SecondBean {
private String stringField;
private int primitiveField;
public String getStringField() {
return stringField;
}
public void setStringField(String value) {
this.stringField = value;
}
public String getThisIsNotGetter(String becauseOfMe) {
return "I am NOT a getter";
}
public int getPrimitiveField() {
return primitiveField;
}
public void setPrimitiveField(int value) {
this.primitiveField = value;
}
}
private static class ThirdBean {
private Object nobodyHasThisFieldExceptMe;
private String stringField;
private int primitiveField;
public int getPrimitiveField() {
return primitiveField;
}
public void setPrimitiveField(int value) {
this.primitiveField = value;
}
public String getStringField() {
return stringField;
}
public void setStringField(String value) {
this.stringField = value;
}
public void setNobodyHasThisFieldExceptMe(Object value) {
this.nobodyHasThisFieldExceptMe = value;
}
public Object getNobodyHasThisFieldExceptMe() {
return nobodyHasThisFieldExceptMe;
}
}
protected void setUp() throws Exception {
bean1 = new FirstBean();
bean2 = new FirstBean();
bean3 = new SecondBean();
bean4 = new ThirdBean();
}
public void testFilteringGetters() throws Exception {
Method[] getters = getters(SecondBean.class.getMethods());
for (int i = 0; i < getters.length; i++) {
assertTrue(
"Method "
+ getters[i].getName()
+ " shouldn't be considered a getter because it doesn't start with 'get'",
getters[i].getName().startsWith("get"));
assertEquals(
"Method "
+ getters[i].getName()
+ " shouldn't be considered a getter because it takes arguments",
0, getters[i].getParameterTypes().length);
}
}
public void testAllNullFields() throws Exception {
try {
assertBeansAreEqual(bean1, bean2);
} catch (AssertionFailedError notExpected) {
fail("Two beans with all null fields should be equal");
}
}
public void testStringFieldsWithEqualValues() throws Exception {
bean1.setStringField("foo");
bean2.setStringField("foo");
try {
assertBeansAreEqual(bean1, bean2);
} catch (AssertionFailedError notExpected) {
fail("Two beans with same values for string fields should be equal");
}
}
public void testStringFieldsWithDifferentValues() throws Exception {
bean1.setStringField("foo");
bean2.setStringField("bar");
try {
assertBeansAreEqual(bean1, bean2);
} catch (AssertionFailedError expected) {
return;
}
fail("Two beans with different values for string fields should be considered not equal");
}
public void testPrimitiveFieldsWithEqualValues() throws Exception {
bean1.setPrimitiveField(1);
bean2.setPrimitiveField(1);
try {
assertBeansAreEqual(bean1, bean2);
} catch (AssertionFailedError notExpected) {
fail("Two beans with same values for primitive fields should be equal");
}
}
public void testPrimitiveFieldsWithDifferentValues() throws Exception {
bean1.setPrimitiveField(1);
bean2.setPrimitiveField(2);
try {
assertBeansAreEqual(bean1, bean2);
} catch (AssertionFailedError expected) {
return;
}
fail("Two beans with different values for primitive fields should not be considered equal");
}
public void testAllNullFieldsOnSimilarButDifferentClasses()
throws Exception {
try {
assertBeansAreEqual(bean1, bean3);
} catch (AssertionFailedError notExpected) {
fail("Two beans with all null fields should be equal");
}
}
public void testStringFieldsWithEqualValuesOnSimilarButDifferentClasses()
throws Exception {
bean1.setStringField("foo");
bean3.setStringField("foo");
try {
assertBeansAreEqual(bean1, bean3);
} catch (AssertionFailedError notExpected) {
notExpected.printStackTrace();
fail("Two beans with same values for string fields should be equal");
}
}
public void testStringFieldsWithDifferentValuesOnSimilarButDifferentClasses()
throws Exception {
bean1.setStringField("foo");
bean3.setStringField("bar");
try {
assertBeansAreEqual(bean1, bean3);
} catch (AssertionFailedError expected) {
return;
}
fail("Two beans with different values for string fields should not be considered equal");
}
public void testPrimitiveFieldsWithEqualValuesOnSimilarButDifferentClasses()
throws Exception {
bean1.setPrimitiveField(1);
bean3.setPrimitiveField(1);
try {
assertBeansAreEqual(bean1, bean3);
} catch (AssertionFailedError notExpected) {
fail("Two beans with same values for primitive fields should be equal");
}
}
public void testPrimitiveFieldsWithDifferentValuesOnSimilarButDifferentClasses()
throws Exception {
bean1.setPrimitiveField(1);
bean3.setPrimitiveField(2);
try {
assertBeansAreEqual(bean1, bean3);
} catch (AssertionFailedError expected) {
return;
}
fail("Two beans with different values for primitive fields should not be considered equal");
}
public void testBeansWithMismatchingGetterMethodsShouldNotBeConsideredEqual()
throws Exception {
bean1.setPrimitiveField(1);
bean4.setPrimitiveField(1);
try {
assertBeansAreEqual(bean1, bean4);
} catch (AssertionFailedError expected) {
return;
}
fail("Two beans with different values for primitive fields should not be considered equal");
}
}
PS. I'd love to hear about it if you find holes from my tests (i.e. if you figure out scenarios where the assertion doesn't work as one would expect). I'm pretty sure there are some...
Just a pointer: Peter Provost decided to re-do a piece of C# in Ruby and ended up creating a nice little portrait of Ruby's flexibility.
I just noticed going through my blogroll that Jeremy had referred to my CruiseControl article--that is, Part 1 of the article. There's also a Part 2 but I've more than once forgotten to add a forward link from Part 1 to Part 2. I'll try to get that link up there one of these days...
Actually, I've been planning on pulling the articles I've written on my website as well but that might take a while.
In his recent blog entry titled programmers don't make projects fail, Udi Dahan argues (quite correctly, in my opinion) that, well, programmers don't make projects fail. I'll leave reading the blog entry to you but I would like to focus your attention on Udi's closing paragraph on the blog:
Not to end on a doom-and-gloom note, you'd be surprised how quickly you can identify real issues by checking overtime. Of course, the faster you identify these issues, the sooner you can resolve them.
While it's very true that programmers doing overtime is a good indicator of timely delivery being at risk, most projects--I'd dare to speculate--are in fact not aware of the need for overtime until very late in the project when it's already {drum roll, please} too late.
If you're dying to know the solution I have to offer for resolving that problem, don't hesitate to call my 24/7 telephone consulting line at 1-800-ITERATIVE ...
The guys at F-Secure have great examples of Information Radiators in their virus lab.
Someone once sent the following comment on the slides of a TDD classroom training I had done for his company (that someone wasn't attending himself and just checked out the slides from their intranet):
When thinking about TDD I always think about Kent Beck sentence "throw away all my production code but keep my test code" (not verbatim), the principle is that it should be possible to generate production code on the basis of only test code.
Which raises the question, has anyone tried that? While I'm pretty suspicious about such an idea scaling up to "real" systems, it would be interesting to read about academic experiments or something like that. Would it be even theoretically feasible to generate seemingly random bytecode until all the tests just happen to pass (and we'd know we have a working implementation of the system as described by the tests)?
[Disclaimer: I'm not involved with J2ME development myself]
One could say that a technology is not mature these days unless there's a full, high quality development environment available for no cost. For J2ME, there has been NetBeans with some kind of support for Sun's own wireless toolkits but for sworn Eclipse fans that hasn't been much comfort. With the 1.0 release of EclipseME, things are finally starting to look better.
Odeo just went live. I already subscribed and downloaded the desktop client. It'll be interesting to see how this thing gets going. So far, all I can say is "WOW!". If nothing else, you better check out the UI Noah and Evan have set up.
I don't really care, but it's pretty darn hilarious! :)
Michael Harmer blogs about his preference for elegantly sufficient design. In that blog entry Michael defines Michael's design threshold laws:
- For a team to work well together it needs to establish a common, congruent set of design thresholds.
- For a team to be successful it needs to have design thresholds that produce elegantly sufficient designs and code.
Now, there's no way one could disagree with a team having common design thresholds being a good thing. It's easier said than done, however. How do you define a design threshold? I'm pretty sure you can't find a definition that would be considered accurate and would not involve subjective evaluation by an authority recognized as having a good sense for what's elegantly sufficient design. Oh, I'm sure there are plenty of academic studies experimenting with formal, statistical, and what not algorithms for automatically deducing a number from a codebase but, seriously, have those things ever worked on any real world context? Most of the time, guess not.
Among ScrumMasters, the phrase "ask the team" is a good one and an often used one. Consensus is, however, difficult to
achieve.
Quoting James Grenning:
"Consensus is great, but that may never happen. [...] Have a vote on items of disagreement. Benevolent dictator can also help speed things up."
Consensus is indeed a rare luxury in many teams. Voting, on the other hand, seems to work ok most of the time. Sometimes, though, voting on things is simply too costly if the team consists of more than a handful of developers. Besides, how often you get unanimous votes? There's a good chance that someone feels wronged by the evil, evil majority. Another option would be to assign someone to be the code police who says whether a given solution is sufficiently elegant or not. "If the team's unofficial code police says it's good, then it's good" might not be a good criteria in the long run, however, and it's far from ideal considering that the code police rarely represents the whole team. And most of the time it's still a majority vote, not a consensus decision. It seems that there's really no substitute for consensus. Only workarounds with trade-offs.
In order to achieve the best performance your team is capable of, the concept of elegantly sufficient must be part of the team's culture--shared by everyone on the team. Once you've got that, it's likely that you've got a jelling team. Congratulations. You're probably kicking the living crap out of your competitors.
Jamis Buck, one of the few with commit rights for Ruby on Rails, has posted a Rails tip of the day on his blog. In the blog entry, Jamis explains how the action method continues its execution even after a call to redirect_to or render. To someone with years of experience on Java Servlets, it seems a bit surreal that someone would actually think that the execution stops there. Then again, I do realize that people coming from other technologies than J2EE, for example, might not have ever seen a framework that works this way. Especially since they've probably already been amazed to death a dozen times by everything else in Ruby and/or Rails.
Speaking of which... Little red gems like this still feel like someone was rubbing Ruby on my face, knowing that I'll have to deal with a crappy WebLogic Portal application for the next two weeks:
redirect_to(...) and return
Yeah, I also thought that was a ridiculous thing to say.
Until I saw this at pearsoned.co.uk.
I just had to share this quote with you (via Jeremy Miller):
"[doing CMM paperwork] is like paying protection money to the mafia."
Now, I'm not completely against CMM(I). I just find that companies and assessors tend to interpret it the wrong way most of the time.
I just skimmed through a Gamasutra article titled Game Coding Complete: Smart Design Practices (a book excerpt from an O'Reilly title) which lists a few practical tips for covering your ass codewise. Coming from the game development world, some of the practices are a bit irrelevant for the typical modern day business application developer doing J2EE but some of them hold equally well both sides of the chasm.
Avoid hidden code that performs nontrivial operations
The first practice is what I consider to be of high importance. The principle of least surprise is an important one and we should remember to keep that in mind when pounding away in our IDE's. Encapsulation is a good thing if done right but it can be misused for hiding details that the client code (or its author) really should be informed about. The obvious example is a getter method that one assumes to be a dirt-cheap operation while it's really hitting the database on every call. However, it's not about the performance -- it's about us knowing what our code is doing.
Keep your class hierarchies as flat as possible
Earlier today, a discussion passed the subject of frameworks that require one to extend a base class (examples include JUnit and Struts, among others) and how that's a smell, regardless of whether this restriction is a conscious design decision or a necessity dictated by the constraints of the technology in use. The fewer levels of inheritance in your system, the easier it is to understand--and evolve.
Be aware of the difference between inheritance and containment
Related to the previous point, it is important to realize when inheritance really is appropriate. In fact, I'd say that most of the time it's not! Aggregation has long proven to be much more flexible than inheritance. Inheritance is a good tool. It's just not for nails of all sizes.
Avoid abusing virtual functions
While virtual functions are not an issue for Java developers, the underlying theme of avoiding situations where bad things can happen is not to be dismissed lightly, either. Using the very latest features of the very latest technology or programming language might not be the best choice for the project or the company. "Right tool for the job" should not exclude the fact that there's people involved in software development, believe it or not. Thinking about your "audience" is hardly ever a bad idea...
Use interface classes and factories
'Nuff said. Abstraction is a powerful technique. Provided that we don't abuse it, that is. I've recently been subjected to a relatively big codebase on a portal project. Beyond the usual procedural-code-written-in-Java terror, I've come to realize that one of the major obstacles for getting new people up to speed quickly is that the system is missing at least one layer of abstraction between the application code and the underlying portal product's API.
Use streams in addition to constructors to initialize objects
This last one is very much game development specific so I don't have much to say about it. It makes sense, but I must say I don't quite see why McShaffry included this particular practice among the others. It's almost like he's mixing two levels of abstraction here ;)
I spotted a great piece of information from a link in Mike Clark's post on the ActiveRecord library used in Rails.
That piece of information was an article at SitePoint.com about something called modified preorder tree traversal. It's essentially a fast algorithm for query operations on a hierarchical set of data stored in a relational database -- a problem we usually tackle with an adjacency list, i.e. tacking a "parent_id" column on each record and perform a series of database queries in order to fetch a (sub)tree of records.
The modified preorder tree traversal algorithm is a funky one. I won't explain it in detail here (go read the SitePoint article for an excellent description!) but it's basically a way to structure your hierarchical data in a relational database in a way that let's you fetch an arbitrary subtree from the database using just two (2) SQL queries. The first one is for fetching details for the root node of the subtree and the second one is to fetch all the children and grandchildren of the root node.
The trade-off is two-fold:
1) This solution is less intuitive than the adjacency list approach because of its algorithmic flavour
2) This solution makes updating/deleting/inserting records a bit expensive because we need to update the index (the index is what makes the SELECT operations lightning fast)
Check it out if you haven't heard of it already. I have to admit that I've never been good at algorithms nor specifically interested in them. Yet, I'm excited to learn new ones that are actually useful!
Thanks, Mike!
Today, just a few hours ago, for the first time in my life, I met someone who writes wikipedia (the Finnish wikipedia to be more accurate).
Meet Joonas:
Well, actually I had met him before but I didn't know he's writing that stuff. Joonas is an ex-colleague, a future colleague, and a very nice guy in general. And he's admitted being seriously addicted to writing the wikipedia. It's something about those red links with a question mark urging for your attention, I guess...
Tim Bacon blogs about retronyms. He also links to Scott Ambler's old article where he turned the four values of the Agile Manifesto around. It's often interesting how "multiplying by -1" can change the perspective of things.
Tim, by the way, is an ex-ThoughtWorker (who in XP2005 mentioned something about big consultancies like Accenture, IBM, EDS and the like being the root of all evil in IT today :) just like Rachel, apparently, who blogs about the combination of an intensive project and long commute eating up a lot of energy.







