- Open Source Tools for IT Automation
Anyone ever tried this?
ThoughtWorks' Agile Project Management application
Adewale Oshineye (feed)
Aidan Rogers (feed)
Alan Francis (feed)
Alex Ruiz (feed)
Andres Taylor (feed)
Andrew Trigg (feed)
Aslak Hellesoy (feed)
Ben Griffiths (feed)
Benno Rice (feed)
Bret Pettichord (feed)
Brett Dargan (feed)
Brian Oxley (feed)
Carl Ververs (feed)
Chaoqun Li (feed)
Charles Lowell (feed)
Chris Brown (feed)
Chris Matts (feed)
Chris McMahon (feed)
Christian Kvalheim (feed)
Christian Taubman (feed)
Craig Cruden (feed)
Damian Guy (feed)
Darren Hobbs (feed)
Dave Astels (feed)
Dragos Manolescu (feed)
Duncan Cragg (feed)
Dustin Aleksiuk (feed)
Fabio Gavilondo (feed)
Fred George (feed)
Garrett Smith (feed)
Geoff Oliphant (feed)
Greg Luck (feed)
Greg Wdowiak (feed)
Gregor Hohpe (feed)
Griffin Caprio (feed)
Ivan Moore (feed)
Jack Bolles (feed)
James Mead (feed)
James Ross (feed)
Jason Huggins (feed)
Jeff Patton (feed)
Jeremy Stell-Smith (feed)
Joe O'Brien (feed)
Joe Walnes (feed)
Jon Eaves (feed)
Jon Tirsen (feed)
Jonathan Rasmusson (feed)
Julian Simpson (feed)
Julian Simpson (feed)
Karthik Chandrasekariah (feed)
Kerry Todyruik (feed)
Keshav Murthy (feed)
Kurt Schrader (feed)
Marty Andrews (feed)
Matt Clarkson (feed)
Matthew Deiters (feed)
Matthew Ueckerman (feed)
Mike Mclaughlin (feed)
Mike Melia (feed)
Mike Roberts (feed)
Mike Williams (feed)
Muness Alrubaie (feed)
Narayan Raman (feed)
Narayan Raman (Sahi) (feed)
Nat Pryce (feed)
Nathan Arthur (feed)
Obie Fernandez (feed)
Obie Fernandez (JRoller) (feed)
Owen Rogers (feed)
Paul Coia (feed)
Paul Holser (feed)
Paul Julius (feed)
Paul Miles (feed)
Peter Barry (feed)
Rene Duquesnoy (feed)
Richard Watt (feed)
Shane Duan (feed)
Simon Stewart (feed)
Steve Freeman (feed)
Thomas Looy (feed)
Tim Bacon (feed)
Tim Velvick (feed)
Wilkes Joiner (feed)
William Caputo (feed)
__ThoughtBlogs-Admin (feed)
On Day One, I picked Josh Bloch's brain for a bit about whether the BGGA closures proposal was redeemable if the gnarlier bits might be removed, leaving it basically with function types. It was cool to mingle with the Java "rock stars", if only for a moment.
I enjoyed Neal Gafter's Day Two talk "Closures Cookbook" immensely. He gave a very clear exposition of the BGGA proposal and the use cases propelling it.
Right out of the gate, he started with a disclaimer: Google is open to multiple parallel investigations of closures but is not currently prepared to commit to any particular proposal.
The cool bit is that closure literals can be used as instances of one-method interface types whose method parms and return type are compatible with those of the closure:
Runnable r = { => doWhatever(); }
r.run();
Callable<String> cs = { => "result"; }
Comparator<String> reverse = { String s1, String s2 => s2.compareTo(s1); }
ItemSelectable is = ...;
is.addItemListener( { ItemEvent ev => doSomething(ev, is); } );
Apparently there are technical reasons why this couldn't be done for abstract classes with one abstract method, didn't quite get the picture...
Also considered were aggregrate operations, near and dear to my heart:
double highestGPA = Double.MIN_VALUE;
for (Student s: students) {
if ( s.graduationYear == THIS_YEAR ) {
int gpa = s.getGPA();
if ( highestGPA < gpa )
highestGPA = gpa;
}
}
double highestGPA =
students.filter( { Student s => s.graduationYear == THIS_YEAR } )
.map( { Student s => s.getGPA(); } )
.max();
I just love how the second reads -- nothing like method names to make intent clearer.
An extended example involving an API for timing units of code:
interface Block<R, throws X> {
R execute() throws X;
}
public <R, throws X> R time(String opName, Block<R, X> block) throws X {
long startTime = System.nanoTime();
boolean success = true;
try {
return block.execute();
}
catch (final Throwable ex) {
success = false;
throw ex;
}
finally {
recordTiming(opName, System.nanoTime() - startTime, success);
}
}
int f() {
time( "opName", { => someStatements } );
time( "opName", { => return computeResult; } )
}
Yowza. Nice how it genericizes over whatever exceptions the block may raise (including none), and whatever the block might return (including nothing). Note the use of "safe re-throw" by marking a catch parameter final (proposed for JDK7).
Alex Buckley and Stanley Ho gave a nice summary of the first-class language and tooling support for modularity in Java (JSR 277). Seems a JAM module would be able to leverage OSGi bundles and repositories? Nice.
The Java Persistence API 2.0 talk was packed. Ridiculously packed. Fire marshal, anyone? People continued to stream in well into the presentation. One guy ended up accidentally kicking separating my MacBook power supply from the pluggable portion of it. Not so much as a "sorry, my bad" -- never looked back. I understand there's a certain amount of Asperger-style intense focus at a geeky conference, but come on. Sorry if I seemed a bit peevish, but several hot buttons were hit in this one: overcrowded room, disregard for personal space, cell phones ringing after several admonishments to silence them, relatively shrill speaker a bit trigger-happy on the slide flipper ... I guess my bitching about it was way more annoying to the guy in front of me, as when I uttered the line, "As a courtesy to others, please silence your cell phones", he shot back with the timeless classic, "Why don't you silence yourself, dude?" Cue the slow clap.
Anyway, I didn't get that much out of the JPA talk. I'm not doing much RDBMS work these days, but at least I have a sense of where to look for JPA info.
I bailed out of the talk "Unit Testing DB Operations with DBUnit" a shade early to catch a power nap -- I had no idea how exhausted I'd be after 1.5 days at the conference. That said, I scheduled a number of sessions and BOFs -- perhaps next time I'll pace myself a bit better. Besides, I've used DBUnit before, and it it quite nice -- not much new ground covered for me.
"Boldly Go Where the Java Programming Language Has Never Gone Before" -- Geert Bevin's talk's premise was that "You don't have to master new languages, tools, or libraries to deliver applications that go much further than what the standard Java platform provides." He gave compelling demonstrations of Terracotta, an OSS clustering solution for the Java platform; RIFE, a component-based web framework featuring continuations; GWT; and Google Android. Very nice stuff!
"Building RESTful Clients with JavaScript, Ruby, and JavaFX" -- not much here you couldn't get from an introductory article on REST.
Ola Bini of ThoughtWorks gave a talk about TW's use of JRuby. As an ex-ThoughtWorker I was eager to hear about what TW's been up to in the Ruby world -- clearly, quite a lot. I left TW just as it was beginning to pursue and land Ruby/Rails work. Right now, 40% of its US revenue comes form Ruby/Rails work. Surprising to learn that test suites run more slowly often in JRuby than in MRI -- less opportunity for JIT leverage, it seems. Often they run test suites in MRI pre-commit, then with JRuby in CI build.
"Cooking Your Own Groovy Builder: A Step Forward into Domain-Specific Languages" -- nice exposition of the Builder support for languages that describe hierarchical structures such as XML documents and Swing widgetry.
Some random thoughts from Day 1 of JavaOne 2008 (belated):
Wi-Fi connections spotty at best. Kind of disappointing they couldn't handle the traffic they could have reasonably expected.
"JRuby: What, Why, How...Do It Now!" -- Nice JRuby overview. An admonishment not to be scared to let go of static types -- nice. Interesting how Groovy lets you go either way, sticking with the manifest typing of Java or introducing latent types as you please.
Demonstrated blocks for deferred invocation, and their uses in internal collection iteration and encapsulating transactional code -- important use cases for their potential inclusion (closures) in the Java core language. I wonder if such language features are better left to the other JVM-based languages that are sporting them already, rather than over-complicating what started out as a simple language. Josh Bloch speaks often of a "complexity budget" for a language, and that perhaps Java is overspent.
Much of Rails code is created on startup. Interesting. Cool that Ruby allows you to define classes and methods at runtime, and to open up classes for such additions. Cooler still that in JRuby, core JDK classes become open (even those that are final). Apparently the term for opening up and tweaking core classes in this way is "monkey patching" -- derogatory term in the Python world, celebrated in the Ruby world.
JRuby leverages native threading of the JVM for better performance, as opposed to the "green threading" of the MRI. There is a jirb analogue to irb in JRuby -- nice.
"require 'java'" to use JDK classes in JRuby code.
"require 'irb/completion'" in jirb to enable auto-completion in the console. Sweet.
Java methods can be invoked in their regularCamelCaseWay or via_lower_case_underscored_names.
Plenty of help for building Swing apps in JRuby -- Cheri::Swing, Profligacy, MonkeyBars
"More Effective Java" -- New edition of Bloch's "Effective Java" is out -- covers new ground of generics, annotations, enums, concurrency libs, etc.
Use wildcard types, bounded or otherwise, generally only as method parms, not as return types.
'PECS' -- Producer extends, Consumer produces -- mnemonic for remembering when to use ? extends X versus ? super X. If a method is both a producer and consumer of X, no wildcards needed on the generic type. Users should not have to think about wildcards to use your API.
Enums -- do not rely on ordinal() for business logic, if you need to use an integer distinguisher as a field for each enum, use a constructor with an integer parm. Don't depend on which ordinal() integer is assigned to each member of the enum. Good discussion of EnumSet and EnumMap. Bit fields are obsolete in Java.
The power of readResolve() to enforce singularity of singleton Serializables has been oversold -- readResolve() works only if all fields of the Serializable are transient.
Enums are inextensible, but can implement interfaces and each member of the enum can supply an implementation.
Good discussion of various lazy-init techniques.
Java 5 memory model enhancements apparently make double-check locking idiom work now.
"Upcoming Java Programming Language Features" -- Alex Buckley, spec lead for JDK 7 JSR, speaks of stewarding the "moral and technical integrity" of Java.
"A good application is rich; a good language is pure." Gosling, about adding features to a language: "Just say no, until threatened with bodily harm". Tougher to add language features due to the explosion of interaction between the features. In an app, features relatively rarely interact, and more is considered better. Not so with language features. With a language, fewer, more regular features are better.
"Respect the past": new keywords shouldn't break existing code (a la 'assert', 'enum').
"Respect the future": allow room for syntax to breathe. Syntax/semantics of a feature should not conflict with those of existing or potential features (quite a tall order!)
"Respect the model": every language reflects a model of computation. Java's model: general-purpose, class-based, OO, concurrent, civilized relationship to APIs, aligned with JVM. When evolving a language with features, have those features enable more regular and abstract programs.
Principles that recognize the Java model:
Under consideration:
Not of interest:
"GUI Testing Made Easy" was a nice introduction to the FEST library by former ThoughtWorker Alex Ruiz.
"Practical Applications of Static Bytecode Analysis and Transformation for the Java Platform" -- great demonstrations of tools that use libraries like ASM for tweaking bytecode in interesting ways:
"Tips and Tricks for Using Language Features in API Design" -- lots of material to cover in a very short time. I felt the speaker just ripped right through some topics that to me were non-obvious. Slow down! Interesting to learn a potential good use for wildcarded generic return types: return of an internal collection without having to copy it (callers won't be able to add/modify).
Be wary of interface covariant returns -- great for concrete impl classes, but in branching interface hierarchy, watch out.
If you're going to add an exception type, maybe make it carry more info other than just a new name? Cause? How to recover? Also, in libraries, do take care to add serialVersionUIDs to your exception classes -- Exceptions are Serializable.
Who'd have thought it? Bananas kill warts.
Sometimes, I wonder if I should just devote this blog to something other than "mainly tech" :)
I just read Thread Signaling from Jacob Jenkov. It is fine as far as it goes to introduce the reader to Object.wait() and Object.notify().
But it has one fatal flaw: it uses a literal java.lang.String for coordinating between threads. Why is this wrong?
Strings are interned by the compiler. To quote the javadocs: All literal strings and string-valued constant expressions are interned. Using a literal string means that any other code anywhere in the JVM, even in other libraries, which use the same String literal value all share the same object for wait() and notify(). This code:
public void dastardly() {
"".notify();
} will wake up a thread waiting on empty string, including one in utterly unrelated code.
Don't do that. Instead, create a fresh Object for coordinating threads. This age-worn advice for lock objects (synchronize(lock)) applies just as much to objects used to coordinate threads.
Jean-Marie Dautelle on Realistically real-time, or getting real-time-like behavior from the non-real-time JVM.
I'm at JavaOne this year, my first trip to the big dance. Based on the rock-concert lines forming for the first General Session, I'd say the conference is doing pretty damn well.
Flight into SFO from DFW last night was without incident. It was remarkably easy to get to my hotel downtown, about six blocks away from the Moscone Center -- hopped the AirTrain to the BART Station, quickly purchased a ticket to the Powell station, hopped on, and twenty minutes or so I was five blocks away from my hotel. Great success!
I'm registered for the following Day 1 technical sessions/BOFs:
More updates as the talks warrant.

(image taken from justpic's photostream)<project name="OnceAndOnlyOnce">You can see that any other use of the fileset will be able to refer to it by ID, rather than explicitly declare it again. One of the scariest builds that I ever saw was 4,000 lines of XML in a single file. One of my erstwhile colleagues spent a morning going through it and replacing filterset declarations with references to one filterset. It's such a useful feature to have in a build tool, and a fine piece of advice to give to someone who just started out writing build scripts.
<fileset id="output_files" dir="${build.dir}">
<include name="duplicato-*.jar" />
</fileset>
<target name="copy_stuff">
<copy todir="${special.shiny.dir}">
<fileset refid="output_files" />
</copy>
</target>
</project>
One of the most common causes of sporadic bugs in swing applications is doing things on the wrong thread. Most common of these is when a thread that is not the Event Dispatch Thread does something that updates the gui. Its very easy to do accidentally as seemingly innocent operations done on a background thread can fire off event listeners and end up inside code it shouldn't as a result.
CheckThreadViolationRepaintManager from the SwingHelper project is a very useful class that can be easily plumbed into a Swing application to report any wayward threads getting into gui code.
Also from the same stable is the EventDispatchThreadHangMonitor which can report when the Event Dispatch Thread spends too long outside its main loop (which will result in a sluggish and unresponsive gui).
So I was all fired up about migrating to wordpress, due to the rot this blog has suffered over time. (The category links have been broken for nearly 2 years now I think). I got as far as the following line in the (ahem) 5 minute install guide:
Create a database for WordPress on your web server, as well as a MySQL user who has all privileges for accessing and modifying it.
And now it all seems like way too much effort. I'm incredibly lazy when it comes to blog tools. Gone are the days when I would happily spend half a day tinkering with the tool prior to writing a 10 minute post. And I'm sick of blasted relational databases. A blog is just a bunch of text snippets with a few bits of metadata around the edges. Why not use a perfectly good filesystem for storing what is so easily represented as a bunch of files? It might even stand a chance of holding my attention long enough for me to finish installing it.
I really want to blog more, but I need the feedback of comments to help keep me going. Every time I've tried tinkering with movable type comments to allow me to turn them back on its been buried in spam within seconds, and I can't be bothered figuring out which magic combination of plugins, captchas, blacklists and runic inscriptions I need to make it work.
I'm off to find some incredibly tedious housework to do that might make farting about with MySql seem like a reward and a treat.
One of my most visited posts is this one written in 2003 about a couple of little known classes in the JDK for generating unique identifiers, also known as GUID's or UUID's. Java 5 and later now also has the UUID class. Universally unique identifiers for everyone!
Agile is dead. The word is too easy to slap onto any old thing in an attempt to jazz it up. It's also pretty easy to use as a pejorative term by those who have no interest in improving. Let's take a typical interaction:
"We're doing agile development. By using agile techniques we can work more effectively and our software is easier to change, with fewer bugs. The agile approach lets our customers steer the project while it's running to maximise return on investment.""Agile techniques? I've heard about them. Isn't agile software development just an excuse not to spend time doing design and analysis? How can you run a project without nailing down all the requirements and design in advance? Agile approach? No thanks!"
In my head, I like to replace the word 'agile' with 'professional' and 'modern'. To me the above conversation thus sounds a bit like this:
"We're doing professional development. By using modern techniques we can work more effectively and our software is easier to change, with fewer bugs. The professional approach lets our customers steer the project while it's running to maximise return on investment.""Modern techniques? I've heard about them. Isn't professional software development just an excuse not to spend time doing design and analysis? How can you run a project without nailing down all the requirements and design in advance? Professional approach? No thanks!"
It also works when talking about software frameworks.
"We've built a software framework to enforce a standard approach to all applications and maximise reuse of common components. All a project team has to do is work to the common interface and conform their design to the framework. Sharing common software components maximises standardisation between projects."
I hear:
"We've built a software nightmare to enforce a mediocre approach to all applications and maximise reuse of inappropriate components. All a project team has to do is work to an inappropriate interface and conform their design to the nightmare. Sharing inappropriate software components maximises mediocrity between projects."
(Just to clarify, I'm a big fan of libraries. A library is something that you use. java.util.collections for example. A framework is something that (ab)uses you.)
After almost 5 years, I find myself no longer working for ThoughtWorks. Moving on was a hard decision but it was time for a change. I'm looking forward to my new job, but I'll miss being '@thoughtworks.com'.
I won't miss Lotus Notes.
Nobody who can spell HTML would be surprised if you launched a Web 2.0 company and chose to use Rails to build your site. On the other hand, one of the ways startups beat the competition is by taking the road less travelled, by using a language considered wierd or niche by everyone else. Success can lead to the language being noticed and becoming more widely accepted.
I was pleased to discover that Slideaware have migrated from Rails to Erlang for their online powerpoint collaboration application. Not because I don't like Rails, but because I really like Erlang.
It's not friendly and it makes it really hard to pay for stuff.
Has anyone ever actually had a smooth user experience with Paypal? Every single time I've tried to use it I've had problems.
The new credit card loop of death. A particular favourite. This is where paypal keeps insisting that 'this card has already been registered' while steadfastly refusing to let me actually use it to pay for stuff, eventually looping back to the 'add card' screen for another fun go around.
Amnesia. Several times paypal has let me go all the way through adding a new card, accepted it and then just forgotten all about it, forcing me to add the card again. Often leads to another free trip to the loop of death above.
Insisting that a payment has already been made (for an item on ebay) and refusing to let me continue, despite ebay having precisely the opposite opinion. Makes the whole cute 'an ebay company' logo look like some kind of ironic joke.
Workflow bugs in little-used ancillary features are one thing but... this is paypal. One might consider the workflow around, you know, 'paying for stuff' to be something of a core function?
There's a pattern I've used with great success a couple of times now that tends to provoke strong reactions in developers when they first see it. I've had comments along the lines of "that's horrible!", "ugh" and "that's way too much work". The pattern is this: the encapsulation of simple built-in types within domain specific classes. Sounds simple and it is.
Lets take a concrete example:
public class Customer {
private final String firstName;
private final String familyName;
private final int ageInYears;
private final int heightInCentimetres;
public Customer(String firstName, String familyName, int ageInYears, int heightInCentimetres) {
this.firstName = firstName;
this.familyName = familyName;
this.ageInYears = ageInYears;
this.heightInCentimetres = heightInCentimetres;
}
}
Fairly standard stuff. But note the constructor signature: string, string, int, int. Not really very expressive and exceedingly easy to get the parameters out of order. But who would get someone's first and last names mixed up? Ask any Chinese person how often that happens. They place their family name before their given name. Also, strings and integers are not usually domain concepts unless you are writing a compiler. Someone's first name is not interchangeable with their last name the way two strings are. So how about this:
public class Customer {
private final FirstName firstName;
private final FamilyName familyName;
private final Age age;
private final Height height;
public Customer(FirstName firstName, FamilyName familyName, Age age, Height height) {
this.familyName = familyName;
this.firstName = firstName;
this.age = age;
this.height = height;
}
}
It is at this point that most developers recoil. No way do I have time to add an entire class just to wrap a string! Or two entire classes in this case! Actually, it's four new classes. All of which I wrote while writing this post. There is a reasonable amount of boilerplate. Including toString, equals, hashCode and a getter makes for about 40 lines per tiny type, almost all of which can be condensed into an IDEA template. And most systems have a finite number of domain concepts so the rate of adding these tiny types isn't very high and drops off fairly quickly.
But why do this? I consider it playing to the strengths of a statically typed language. Java will never be as Ruby as Ruby, but it can be much more Java than Ruby ever will. All sorts of useful things start to happen when the library types and primitives have been banished from your api. Now the compiler can spot transposition errors. Equals and hashCode can be implemented with domain specific semantics. It's much harder to accidentally pass dollars into a method that was expecting pounds sterling (but actually took a double so it could have been anything). Readability is greatly improved. Automated refactoring, code completion and code navigation all gain a new level of power. 'Find usages' on the FirstName class produces far more useful results than doing it on the String class.
You probably still don't fully believe me if you haven't tried it, but this is one of those times where cognitive dissonance has got it wrong. It really is an exceedingly useful approach.
Almost without fail I see certain errors repeated on every single software project I come across. The projects that successfully dodge these pitfalls almost always do so because someone on the team fell into them once before and swore they wouldn't do so again. Those of you who haven't yet been burned by this class of error will almost certainly protest about complexity or wierd design choices in the code made by those who have.
Who are these heinous kingpins of crime in the bug ghettos of the software world? Its a work in progress, but the initial contenders are:
Those of you who've been beset in the past are nodding right now, those who haven't are probably saying, "they don't seem very complicated."
Which is exactly why they'll get you sooner or later. Then you'll remember this post, and you'll nod.
It's been kindly pointed out that my feeds and half my category links are broken and have been for a while. Probably nobody is left who still actually uses a browser to read blogs, but, as this dovetails rather precisely with my assumptions about readership size; and faffing with moveable type templates rates somewhat lower than not, it may take a while before it all gets sorted. Apologies to anyone who's still committed enough to make the effort, I'll try and get round to sorting it.
The sounds of New Years in London: 10 minutes of fireworks, followed by several hours of sirens. Have a safe celebration everyone.
During a recent discussion with some colleagues about which technology to choose for a project I mentioned the importance of tool support, particularly around the IDE. I found myself surprised by the wide range of opinions about the importance of tools. Not about the specifics of whether IDEA was better than Eclipse or VS2005 with Resharper, but about how much importance should be given to tool consideration when choosing a development technology.
Let's say the team has free reign about language choice and has narrowed the decision to Java or Ruby. Both languages are known to the majority of the team. At this point, for a modern project process (lightweight / agile) I would factor in the team size and strongly advocate Java if the team had more than about 3 to 4 developers, justified purely by the superior team support capabilities of IntelliJ IDEA and Eclipse. By which I mean their code exploration and refactoring capabilities.
This is where the arguments start. Er. This is where this particular argument starts.
A typical response might be, "as an experienced developer, while I find automated refactorings useful, I don't need them and certainly wouldn't let my technology decision be swayed by whether a flashy IDE exists. That's just laziness. Developers were refactoring by hand years before refactoring IDEs existed. The improved productivity and less lines of code required with Ruby outweighs any time saved from a few keyboard shortcuts."
This isn't a bad counter-argument. For an individual developer working alone.
With sole access to a codebase that I wrote entirely myself, I'd generally agree. I might disagree with the implication that the time saved by the keyboard shortcuts isn't that significant. I'd love to see a study done where a team had to refactor a codebase and add a feature with a modern IDE compared to another team doing the same thing with Emacs. Moving on - the point that this response misses is that there is a team working on the code not just one developer. I believe the value of automated code modification and exploration increases as a function of team size.
Why should this be? With increasing team size there is an increase in communication overhead and achieving a shared understanding becomes harder and takes longer. Each new member added to a team has an exponential effect on the number of lines of communication.
What does this mean? It becomes increasingly likely that decisions and assumptions made in the early stages will be found to be sub-optimal as the project progresses and the team learns. Code won't be in quite the right shape or quite the right place. The domain model will need to evolve and change. A larger team implies a larger system and therefore more code. It will become very unlikely that everyone in the team knows where everything in the code is. Duplication can creep in. For all these reasons a larger team will necessarily need to explore and change the code as the project progresses. Without automated support even changing a method name for improved understanding becomes a fraught task. In a dynamic language automated support is even more important as there is no compile stage to tell you if you forgot to change one of the callsites. With sufficient test coverage this risk is reduced but never eliminated. So what will generally happen is that changes that should be made aren't made as the effort is too high.
Humans build tools. It's one of our most defining characteristics. We build tools to magnify our physical strength and our mental faculties. There's a reason flint axes have been replaced by chainsaws. We should never underestimate the importance of good tools to achieving productivity.
What could follow a day with a 135mm telephoto? A day with a 12-24mm wideangle! Another day spent with a lens I don't use often enough. I though it would be interesting to walk the same route I did before.
Some quite different shots came out, partly because I got a lot more creative in Lightroom afterwards (which itself was a result of trying to salvage a bunch of truly mediocre shots). But also because you have to work really hard to fill a wide angle lens with interest. The number of times I walked to the 'right' spot while looking through the viewfinder and took the camera away to find myself mere inches from smacking right into the object I was focussing on...
Many years ago, when I was young (okay, 2004) and foolish (that's still true), I bought a Nikon 135mm f/2 'defocus control' lens, ostensibly to photograph a wedding.
That didn't work out, but I'd paid for the lens and it was languishing in my camera bag, so, having just upgraded my camera to a D200 I resolved to get out and try using this superb lens.
Here's what I came up with one sunny november day.
I love: the perspective compression (St Paul's looks huge in some of the shots!), the narrow depth of field.
I don't love: the evil purple fringes of doom on some of the high contrast shots at f/2.
Top tips: pick a day with good light. Hand holding this lens needs shutter speeds in excess of 1/200 or faster for my shaky mitts. Alternatively get creative about finding places to lean against or rest the camera on. Both the D200 body and the 135DC lens are made of metal, so we're talking some serious tonnage when you put them together.
All the indoor shots at the Tate Modern were taken either resting the camera on a railing or the donation bucket, coupled with holding up the lens 'snooker cue' style while trying to get down low enough to see though the viewfinder. Expect funny looks while attempting this.
Multithreading, concurrency, parallelism, Core 2 Duo, call it what you will, the revolution is happening. Today.
Chips aren't getting any faster. Intel have quietly dropped references to clock speeds and chip generations in favour of marketing slogans indicating the number of cores per CPU.
Moore's law has had a head-on collision with the laws of physics, with predictable outcome.
The future is about making things smaller and having more of them. We're moving from a world where clock speed doubled every 18 months to one where cores will double every 18 months. Dual core CPUs are commonplace. Quad core is just around the corner. In 5 years time 16 or 32 core chips will be in your desktop.
So here's the opportunity for software platform vendors: be the best at managing parallelism and making it easy for application developers to leverage all those cores to win tomorrow's market. Threads (ie. Java and C# threads) are old technology, and a dreadful way of expressing concurrency. Language constructs such as Communicating Sequential Processes that allow developers to explicitly describe concurrency are far easier to understand and reason about. See also: the book and wikipedia's entries on CSP and process calculus.
Myself I'm hoping the smalltalk vendors pay attention and adapt. They have the advantage that smalltalk is mostly written in itself. Paradigm shifts don't come around that often. Fortune favours the prepared mind.
As readers will know, Apple released Java 6 for 64 bit intel architectures this week.
What you may not know, is that making it your first preference in the "Java Application Runtime Settings" "Java Preference" app in Utilities, fixes a nasty app switching bug you get when using spaces.
That bug is that if you change away from a space and then change back, the Java app you had in focus has gone and it is fiddly to get back.
“Keyboads dirtier than a toilet” (BBC)
It justifies my view that eating lunch at the desk is uncivilised, and that pairing stations should have two keyboards.
Now that everything is USB, maybe we should just carry our own input devices and just plug in when wherever we’re working. Hmmm. Sounds like my dissertation, maybe I should have stuck with it…
JPMorgan is sending me to JavaOne 2008!
Sorry for no posts since November — work has been inordinately busy. I will post from San Francisco.
Curlew Retreat is now open. Curlew Retreat is a luxury villa on a one hundred acre estate located just to the north east of Stanthorpe. It overlooks a beautiful gorge on the Maryland River.
This has been a project of mine for the past couple of years which has now come to fruition.
It is a nice place to get away to. Because of the height which is 2,800 feet above sea level it has a cool crisp climate with frosts about 5 months of the year. Day time temperatures tend to be 4-6 degrees cooler than Brisbane.
My colleague Rod presented me with the following (paraphrased):
public interface Executable<T> {
T execute();
}
The question arose: What if an implementor doesn't have a meaningful value to return?
public class MyExecutable implements Executable<____> {
// ...
}
You could fill in the blank with Object and return null or this, perhaps. However, we agreed that this doesn't communicate as well to its clients the fact that there really isn't a return value and it shouldn't even be used. You can't use primitive void since it really isn't a type, and is a primitive anyhow (forbidden as a generic type parameter). What to do?
How about java.lang.Void?
public class MyExecutable implements Executable<Void> {
public Void execute() {
// do stuff
return null;
}
}
We felt that this clearly communicated that there's no useful return value for the functor. In fact, since java.lang.Void is uninstantiable, the only value the functor could return is null. Nifty, eh? Ever think you'd use java.lang.Void?
Jaggregate internally uses a number of generic functors that really don't need to return anything. I changed them to return java.lang.Void instead of Object, and I'm happy with the results.
I seem to be blog-stalking Keith again.
In his post on Creation under Constraints he uses a post from Andrew Binstock to write about the benefits of discipline on creativity. After all, is there anything more constrained than the form of a Rock’n'Roll song? Bartok had a thing about using the Golden Ratio to structure his work. Even in my misspent youth playing free jazz, the good musicians had an identifiable voice that implied form and structure.
Getting back to the point (there is one? ed.), the phrase You Ain’t Gonna Need It (YAGNI) often seems to be applied at the micro level by using primitive types: I’ll just use a String for this address, I can figure out whether I need a type later. Except that, later there are Strings all over the code, only some of which should be Addresses and, by the way, it turns out that I’ve assigned some company names (also String) to address fields by mistake.
String is about implementation, it’s not expressive in the domain of the code. And I’d double that claim for anything that involves templated collections, when there are three or more levels of nested angle brackets it’s time to turn back.
An alternative view, is to say: I need an Address, I’ll declare an empty type and add features as I discover the need. I don’t expect to need a getBytes() method on Address, but I might well need to ask it for its post code.
Over time, I’ve become more and more convinced of the value of declaring types for everything. I don’t observe this practice as much as I think I should, probably for the same reason I have too many fillings.
There’s been quite a buzz in the narrow world that I inhabit about this recent interview with Donald Knuth. For us “TDDers”, the relevant quote is:
[…] the idea of immediate compilation and “unit tests” appeals to me only rarely, when I’m feeling my way in a totally unknown environment and need feedback about what works and what doesn’t. Otherwise, lots of time is wasted on activities that I simply never need to perform or even think about. Nothing needs to be “mocked up.”
Keith has discussed this point nicely. Personally, in a scarily long time in software (which including tourism at some of the best research labs in the world), I know of a handful of people who can think very hard and then type in a working program of more than 3 lines.
In the meantime, I’m curiously chuffed that the concept of mocking appears to have entered the vocabulary of someone so far away.
As I said, I inhabit a very narrow world.
Wouldn’t it be nice if when an error happened in your application, you could not only see the stack trace, but click on a line and jump to the offending code? This is not groundbreaking stuff, I know, I had this like 10 years ago in C++ and later Java fat clients, and I’m sure other languages & IDEs had it too – but somehow in moving to writing web apps in Ruby, I lost it.
I want it back damnit!
Turns out it’s pretty easy to get back (at least it is if you use textmate) – check it out.
First, to get a custom error page for your project, add something like this to your application.rb :
1 2 3 4 5 |
def rescue_action_locally(*args) render :template => "application/public_error", :layout => false end alias rescue_action_in_public render_action_locally |
Note, if you’re using exception notifiable, you probably want to change the last line to something like :
1 2 |
alias render_404 rescue_action_locally alias render_500 rescue_action_locally |
We use markaby, so our public_error template looks something like this; it’s probably a good idea to keep this simple and not use a layout, just in case the error came from the layout :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
html do head do title action_name stylesheet_link_tag 'error' end body do div.error do div.message do h1 "Whoops" p "We detected an error. Don't worry, though, we've been notified and we're on it." end end end end |
So, it would be helpful to us for our error page to tell us more in our development and staging environments. We do use exception notifiable, so we don’t actually need or want it to say anything else to a real user in production. Adding this to our template, it now looks like this :
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 |
html do head do title action_name stylesheet_link_tag 'error' end body do div.error do div.message do h1 "Whoops" p "We detected an error. Don't worry, though, we've been notified and we're on it." end if RAILS_ENV != 'production' div.stack_trace do h2 "Stack Trace" div { link_to_code $!.to_s.to_s.gsub("\n", "<br/>") } hr div { link_to_code $!.backtrace.join("<br/>") } end end end end end |
What’s that “link_to_code” method in there?
It’s a method in application_helper that replaces any path with a textmate url to open up that file on your local system and jump to the offending line. Check it out :
1 2 3 4 5 6 |
def link_to_code(text) text.gsub(/([\w\.-]*\/[\w\/\.-]+)\:(\d+)/) do |match| file = $1.starts_with?("/") ? $1 : File.join(RAILS_ROOT, $1) link_to match, "txmt://open?url=file://#{file}&line=#{$2}" end end |
That’s it. Suddenly, stack traces are friendly again!
graham-tackleys-mac-mini:~/Documents/workspace/playpen jsimpson$ svn stIn this instance, you can tell that 'a.html' and 'pack.sh' aren't versioned in Subversion because they have a status of '?'.
? a.html
? pack.sh
dir /s/b/a-d | p4 -x- have > nul: 2>missing.txt
find . -type f | p4 -x- have > /dev/null 2>missing.txt
I have really enjoyed the CITCON conferences that I've been to. CITCON is an open space conference about continuous integration and testing - excellently run by Jeffrey Fredrick and Paul Julius. CITCON 2006 in London inspired some of the more advanced features of build-o-matic (which I am really happy about). CITCON 2007 prompted me to produce a much simplified version of jester (which I am really happy about and have had some positive feedback about). CITCON 2008 is going to be in Amsterdam on 3 & 4th October this year; I have registered and I'm looking forward to it - even though on past experience it'll end up prompting me to do lots of extra work as a result!
| Leadership Tool | Purpose in the Church | Purpose in the Corporation |
|---|---|---|
| Preaching | ||
| Teaching | ||
| Training | ||
| Mentoring | ||
| Discipling |
Four weeks ago, life was pretty simple: I was comfortable (but not really happy) in my job, we had a nice apartment, our expenses were low, we had a fairly stable plan for the future, and I was planning on buying a motorcycle. Now, though, everything is different: today was my last day at NetJets, we just bought a car, we’re looking for a new place to live, the future is very uncertain, and it’s not clear if I’ll be getting a motorcycle.
And yet, still, I think today is better than four weeks ago. Crazy, huh?
The story goes something like this: Five weeks ago (to the day), I finally realized (after much prodding from my wife) what I wanted my next career move to be. I wanted to be a Product Manager for a software company, much like I was back before I left Noteworthy Medical Systems, four years ago. I realized how important it is for me to have my hands on real problems that I get to solve myself, and how important it is for me to be on the front lines rather than in an IT department (“in the business, not serving the business”). Nothing against NetJets – they have a truly amazing IT department! – but having tasted life in a software company, I wanted to get back to that. The problem was (five weeks ago) that it’s extremely difficult to get a job as a product manager in a software company, especially in Ohio, so I essentially put that plan on hold for “someday”.
So then four weeks ago (to the day), an old friend/coworker from Noteworthy called me up and basically said “we need you to come back and be a product manager – are you interested?”. Huh, funny how these things happen. I told her I was maybe interested, and spent the next week talking to her, going to Cleveland for interviews, and trying to figure out what had changed since I left. After about a week of this, I was convinced that Noteworthy was in good shape, and that this was a legitimate opportunity, and that I’d really love going back into the product manager job.
So it was easy for me to say yes to the offer – except that Noteworthy is in Cleveland, and we live in Columbus, and Kristina is very happy as a student at OSU. So I was going to have to travel to Cleveland for this job, leaving her in Columbus, and we both know that we don’t do well with full-time travel. So I managed to work out a deal with Noteworthy to travel half-time, working from home the other half, and after much discussion we decided that we could handle that, and I said yes to the offer.
That was two weeks ago (to the day).
So I put in my notice, and we started making plans for how to make this all work. First, obviously, we needed a second car. We’ve never had a second car – our lifestyle just never demanded it, and a car is a huge expense. The question was, which car?
Well, that gets to the next decision, which was to get a dog. As part of agreeing to the travel, Kristina and I made an agreement with each other that we’d get a dog for her, to help keep her company while I’m gone. Well… she wants a big dog. And I think that it’s always better to have two dogs, because they keep each other happy and healthy. And we happen to know of a breeder who has Great Pyrenees puppies for sale, and that happens to be the particular breed of very large dog that we had our eye on… so the plan is to get two huge puppies. Oh, the changes…
So back to the car. Between the two new dogs, and the fact that Kristina is a horticulture student who regularly carries plant stuff around, we decided that we needed a car with lots of space and that’s easy to clean. Minivans were right out, jeeps weren’t big enough, and SUVs are generally a waste of money, so that left the Honda Element – a perfect car for this situation, and one that we really liked. But then that got tough – we were trying to keep the cost low (so we needed a used car), but we like having convenience features (power mirrors) and a nice stereo, and we both like driving stick-shift cars, and we didn’t want one with a ton of miles on it. It is possible to get an Element that meets all these criteria, but we couldn’t find one in Columbus. So we went to Pittsburgh (Monday night) to buy one that we found there, and so far we love it. It took a lot of work to finally settle on that car, and to get the financing sorted out (without having a used car dealer screw us), and get a price negotiated, but it was worth it.
But wait, there’s another consequence to getting these dogs: our current apartment doesn’t let us have pets. (And I wouldn’t put two huge dogs into our place anyway.) So we have to find a new place, preferably a house with a large fenced yard. And we need to rent it because we’ll probably move in two years when Kristina graduates. And our current rent is quite low, and we don’t pay our gas bill, so our housing expenses are about to go way up. And we’re probably not going to find something close to campus with a large fenced yard in a safe neighborhood that’s not too expensive. So that search will continue :)
And finally, all these increased expenses may mean that I can’t get a motorcycle. I have my license (took the class last fall) and a helmet (birthday present, a week ago) and a riding jacket (another birthday present), but no motorcycle. More on this as events unfold.
So, to summarize: new job, new travel lifestyle, new car, new house, new dogs, maybe no motorcycle. Oh, and Kristina’s 30th birthday is in June, so I need to plan that. So yeah, things are a little stirred up around here :) But they’re good.
We have 24" and 30" pairing stations, an intern, freshly roasted coffee delivered weekly, a fridge stocked with caffeine, more caffeine, beer, and Dave's Insanity sauce. We have cool t-shirts and all manner of radiators up on the walls, whiteboards and the Beta Brite. Music is served by our CI/Music server.
The bookshelves are stocked with reference materials, the occasional bottle of scotch, and recommended readings. On the list of recommended readings we've got The Carpet Makers, The Company, The Omnivore's Dilemma, The Eyre Affair, Behind Closed Doors, Bloodsucking Fiends and The Deadline, Men In Hats, Volume I, Don't Make me Think, The Insane are Running the Asylum.
Our favorite radiator is the Friday radiator. Fridays are special: we don't do billable work. Instead we open source, blog (self reference makes this blog entry extra cool), watch educational movies, play Wii on the projector. Here's today's:
Oh, let's not forget the buckets of mice.
Apr 29, 08:30 PM
Amitai Schlair says:
Congrats on the well-deserved good kind of excitement!