Syndicate

OPML
RSS
Atom

ThoughtWorks Studios

ThoughtWorks' Agile Project Management application

Alumni

Adewale Oshineye (feed)
Aidan Rogers (feed)
Alan Francis (feed)
Alex Ruiz (feed)
Amit Rathore (feed)
Andres Taylor (feed)
Andrew Trigg (feed)
Antonio Terreno (feed)
Aslak Hellesoy (feed)
Ben Griffiths (feed)
Ben Hogan (feed)
Benno Rice (feed)
Bernardo Silva (feed)
Bill Six (feed)
Bret Pettichord (feed)
Brett Dargan (feed)
Brian Oxley (feed)
Cenk Civici (feed)
Chaoqun Li (feed)
Charles Lowell (feed)
Charles Tse (feed)
Chris Brown (feed)
Chris Matts (feed)
Chris McMahon (feed)
Christian Kvalheim (feed)
Christian Taubman (feed)
Craig Cruden (feed)
Damian Guy (feed)
Daniel Manges (feed)
Daragh Farrell (feed)
Darren Hobbs (feed)
Dave Astels (feed)
Dave Hoover (feed)
David Kemp (feed)
Dennis Byrne (feed)
Dragos Manolescu (feed)
Duncan Cragg (feed)
Dustin Aleksiuk (feed)
Elizabeth Keogh (feed)
Fabio Gavilondo (feed)
Fred George (feed)
Garrett Smith (feed)
Geoff Oliphant (feed)
George Malamidis (feed)
Greg Luck (feed)
Greg Wdowiak (feed)
Gregor Hohpe (feed)
Griffin Caprio (feed)
Igor Stoyanov (feed)
Ivan Moore (feed)
Jack Bolles (feed)
Jake Scruggs (feed)
James Mead (feed)
James Ross (feed)
James Webster (feed)
Jason Huggins (feed)
Jay Fields (feed)
Jeff Patton (feed)
Jeff Santini (feed)
Jeremy Stell-Smith (feed)
Joe Homs (feed)
Joe O'Brien (feed)
Joe Walnes (feed)
Jon Eaves (feed)
Jon Tirsen (feed)
Jonathan Rasmusson (feed)
Julian Simpson (feed)
Karthik Chandrasekariah (feed)
Kashan Arshad (feed)
Kerry Todyruik (feed)
Kiran Bellubbi (feed)
Kurt Schrader (feed)
Kurtis Seebaldt (feed)
Li Xiao (feed)
Marco Abis (feed)
Marty Andrews (feed)
Matt Clarkson (feed)
Matthew Deiters (feed)
Matthew Ueckerman (feed)
Megan Folsom (feed)
Michael Klynstra (feed)
Michael Ward (feed)
Mike Mclaughlin (feed)
Mike Melia (feed)
Mike Roberts (feed)
Mike Williams (feed)
Muness Alrubaie (feed)
Narayan Raman (feed)
Narayan Raman (Sahi) (feed)
Naresh Jain (feed)
Narla Keshav Ram (feed)
Nat Pryce (feed)
Nathan Arthur (feed)
Niket Kumar Bhumihar (feed)
Obie Fernandez (feed)
Obie Fernandez (feed)
Obie Fernandez (JRoller) (feed)
Owen Rogers (feed)
Paul Coia (feed)
Paul Holser (feed)
Paul Ingles (feed)
Paul Julius (feed)
Paul Miles (feed)
Peter Barry (feed)
Peter F Ryan (feed)
Prashant Gandhi (feed)
Rene Duquesnoy (feed)
Richard Watt (feed)
Ross Niemi (feed)
Ryan Kinderman (feed)
Shane Duan (feed)
Shane Harvie (feed)
Simon Stewart (feed)
Stacy Curl (Digital Compulsion) (feed)
Steve Freeman (feed)
Szczepan Faber (feed)
Thomas Looy (feed)
Tim Bacon (feed)
Tim Goodwin (feed)
Tim Velvick (feed)
Vivek Vaid (feed)
Wilkes Joiner (feed)
William Caputo (feed)
Xiaoming Wang (feed)
__ThoughtBlogs-Admin (feed)

The system I'm currently working on integrates with several external systems, over HTTP, using simple (RESTish) web-services. I really don't want to involve those external systems while testing my own, though; I want to stub 'em out.

My first attempt involved stubbing out HTTP calls using my mocking framework of choice. I'm using RestClient, which I like a lot, and stubbing out RestClient API calls worked quite well. It kept on working quite well for several hours, until I decided to refactor a little, using RestClient in a slightly differently way, at which point it broke completely. Bother. I really don't like having tests coupled to implementation details, so went searching for another way.

FakeWeb looked pretty good, in that it stubs things out at the Net::HTTP layer, which I'm unlikely to refactor out of the picture. In the end, though, it's not really what I wanted. I wanted to be able to do things like:

  • verify the body (and mime-type) of a POST/PUT request
  • dynamically generate responses, based on some aspect of the request (e.g. query parameters)

In short, I wanted a Fake Object, rather than a simple stub.

It occurred to me around about then that we already have plenty of tools for describing the behaviour of web-applications: they're called web-application frameworks! Many of them are too heavy-weight for my purposes, but Sinatra is nicely minimal. So, 60 lines of Ruby code later, I had a little web-app that mimicked one of those external web-services sufficiently for my testing. Win!

But waitaminut. I really don't want to have to start a separate process running my fake web-service, and talk to it using HTTP. That's going to be slow: network I/O isn't cheap. Isn't there some way I can use something like Sinatra but still keep everything in-process?

There is now. ShamRack plumbs Net::HTTP directly into applications built to run on Rack. Which includes all Sinatra apps, as well as Rails, Merb, etc.

Using ShamRack, I avoid the network traffic, making the tests a whole lot faster (about 25 times faster, in my case). Plus, I avoid the complication of having to start and stop an external web-server. Finally, because my fake web-service app is in-process, I get a handy back-channel I can use to setup or inspect it's state during tests.

If you find ShamRack handy, or have ideas about how it could improve, let me know!

The street names surrounding Tufts University are "Harvard Street", "Yale Dr", and "Princeton Blvd".



I've never visited Yale, but the other schools do not have similarly named streets in their vicinity. They do not feel the need to. And even if they did, Tufts would certainly not be one of the street names.



I highly doubt that Medical or Law professionals describe their profession in relation to software.



They do not feel the need to.
This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Friday 7-2-04



We did use my code in the wiki conversion program. And while it was good to finish up that project, this meant we had to start working on the State Map Compiler. A program first written in 1993 in C++, then later re-written in Java in '98. No tests, very long methods, and the documentation gives lots of examples in C++ (which I don't know much about -- it seems like Java, but it most definitely is not.) The point of the program is to take in a simple statement of a 'state machine' and output source code that implements the state machine in either Java or C++. We are going to be adding a C# output option to this program.



Now, at this point, you might be wondering: 'What is a state machine?' Well, let me attempt to regurgitate the turnstile example. A turnstile has two states: Locked and Unlocked. If you try to pass through a turnstile when it's locked, you'll get quite a different response than when it is unlocked. A coin will cause a locked turnstile to become unlocked, but won't do much to an unlocked turnstile. A lot of software engineering problems can be thought of a nothing more than a dressed up turnstile with a few more states. So it's handy to have a program that takes in some information about a finite state machine and then outputs the basic code that you can build your implementation around.



Also, it's pretty interesting to be working on a compiler. Software that writes other software (that, ultimately, will be translated into byte code, and then the byte code will be translated by the virtual machine so that the real machine will know what to do -- quite a process).



Not a bad explanation of a state machine for guy who just learned about them that day: Good job distant-past-jake. I think ended up using a state machine pattern in my code submission to ThoughtWorks later that year.



I later worked on a huge java project that would generate something like 15 classes for every one written class. I soon got very tired of generated code ("Hey, why did my changes go away? Oh, it's a generated class... (next line said forlornly) Guess I better go dig through the xml pit for what to change.")
This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Thursday 7-1-04



There's just one problem with our conversion program: the Double Dash (cue the dramatic music). In FitNesse, two dashes in a row (--) mean strikethrough. But in the old OMwiki, two dashes had no meaning. A fair amount of people use two dashes to separate their thoughts ' as you might expect. So our pages were getting translated with lots of text 'struck out.' Okay, so all we had to do was write a program that looks through all the wiki pages and replaces two dashes with one. Which, it turns out, is not as easy as we thought. The proper way to do this is with regular expressions (mentioned in the previous post), but neither Paul nor I understand them too well. So we looked around for the regex (regular expression) book at OM, but somebody had probably taken it home for some light reading. With that option crossed out we started to build a series of nested if statements. After getting about 5 if's in, Paul turned to me and said 'If Micah sees this code, we're telling him that YOU wrote it.' Fair enough. Well, the problem with nested ifs, as you might know, is that it's hard to keep all those conditionals straight (if this, but not that, and this, that, and the other, wait! No, not the other. Or, uh, let's start again.) so we quickly got lost. Then we gave up. It was just too messy to keep track of how long the string of dashes were. We wanted to change two dashes in a row, but no other length was to be affected. So we started looking up regexs on the web. An hour or so later, it was time to go.



Incidentally, I made my train with only a minute to spare. Really, really, big wind today.



Here's the weird part: I just figured it out while on the train. Using Java's API (a guide to all the classes and methods in the Java library) and some tutorials I downloaded off the web, I talked the 'matcher' into finding dash strings of any length. If the length of that string was two, I replaced it with one dash. If not, I kept the string the same. Nice.



Gotta say, I feel pretty good about being able to contribute something to this project.



So mark down July 1st, 2004 as the day I felt like I really might be able to become a programmer. Since starting at Object Mentor I had contributed almost exactly nothing except for the occasional "You spelled that wrong." But on that hallowed day I actually figured something out before Paul. Maybe I wouldn't have to go back to teaching high school remedial physics and hating Sunday nights because of what Monday promised. Heady thoughts.



Interestingly enough Jay Fields wrote a blog post about the "Spellchecking Pair" a few years later. He makes some good points about matching the levels of programmers but:

A. That's not always possible.

B. I'd feel pretty bad if I was a junior guy on his team when he wrote that post.

C. Inexperienced devs already feel like they are worthless -- try not to make them feel worse.



Still it's important to talk about the problem -- you want to bring developers along but sometimes the impedance mis-match can really frustrate both developers. I generally err on the side of "pairing increases the long term health of the project," but of course their are exceptions. It's just that the exceptions have a nasty way of becoming the rule.

Release Notes

  • Although I had provided a deprecation warning for people using the now renamed Mocha::Standalone, I had assumed people wouldn’t be explicitly loading the mocha/standalone.rb file. It turns out this assumption was incorrect at least in the case of RSpec. This is now fixed.

While I’m coding, I usually have a bunch of very helpful pixies hanging around my desk. (They’re Dan’s pixies really, since he thought of them first; I’m just borrowing them.)

The pixies are bored, and just waiting for a job to do. So, when I’m coding a class, they look out for opportunities to help out that class. When I’m coding the Game of Life, for instance, I write a Gui class that lets me toggle the cells on the grid. Then I have to work out what happens when I toggle the cells.

I could do it in the same class - in the gui - but fortunately the pixies step in to prevent me making these poor design decisions. “Oh, I’ll do that for you!” one of the pixies calls out. (They usually start with this phrase, and they’re all called Thistle.)

“Thanks, Thistle! Do you know what you’re doing?”

“Um, not really. What’s toggling a cell? Why’s that valuable? What is it you want me to do for you again?”

“I need you to handle the cell living and dying when I toggle it.”

“Oh, okay!” Thistle says. “I don’t like the ‘and’ word so much, though. It makes me feel like I’m doing two things at once. What do you call that? The living and dying thing?”

“Hm.” I think about it while the pixie taps his foot impatiently. “I’d call it a lifespan, maybe. Can you handle the cell lifespan for me? Just let me toggle the cells. I also need you to tell any observers that there have been some changes to the cells, and give them a way of finding out where those changes are. I think they’ve already got an idea of what they want there.”

“Really? Both things?”

“Well, there’s no point doing one if you don’t do the other. It’s all part of the same role.”

“If that’s what’s valuable to you then I’ll do it,” he says. “Just pretend I’m there for the moment; I’ll be back when you need me.”

“Fine,” I say. So I use a mock pixie in place of the real one. I create an interface which does what the pixie’s going to do: IHandleCellLifespans.

(See, it’s an interface that starts with “I”, and it represents a role that the pixie is playing for me. This is a role-based, anthropomorphized interface.)

So, now we have code which compiles. Of course, the real code in the Gui is null, or maybe a null object pattern - I might create something like IHandleCellLifespans.KILLING_THEM_ALL if I’m feeling particularly mean. But that’s all right, because Thistle the pixie will step in when it’s time.

So, I run the code. I’ve usually written an automated scenario. It doesn’t matter whether I run the scenario or step through the game manually; both result in the same thing happening, or not happening - no matter where I click the mouse, no cells appear. Pixies are notoriously unreliable.

Since I can’t rely on the pixies, I inject a new class to handle the dependency instead. I decide to call it the Engine, for the moment, and I write an example of how to use it and what it should do for me.

The next step is the Next button. I think about how this would work in the Engine, and start writing some code to show how the Engine needs to behave. I’ll need to calculate the number of neighbours, and apply the rules accordingly.

One of the pixies pipes up, “Oh, I’ll do the neighbours!” and another one says, “Oh, I’ll handle the rules!”

“Fantastic!” I’m so trusting; I always forget what these pixies are really like when it comes to getting the work done.

“If I’m going to count the neighbours,” Thistle says, “I’ll need some information about where I’m counting from, and what’s around me.”

“Ah, I can get the information from the cell itself,” I say.

“No, don’t do that. It’s fine where it is; I’ll just sit inside the cell and do it from there. Can you give me something that lets me know where the other cells around me are? Then I can do the work for you.”

“Sure,” I say, “the Engine knows where the life is. I’ll just give you access to the Engine and let it play that role for you.”

“Can’t I do it instead? I’m bored,” one of the other pixies asks. “Just give me the information from the engine, and let him talk to me instead.”

“Um, Okay.”

Of course, when I try to run it then I find out that all the pixies have mysteriously vanished, and I end up assigning the role to the Engine anyway, or one of its anonymous inner classes. Having it defined as a different role means that it’s easy to move this responsibility around. Maybe I’ll create a World to look after the cells, and let that do the job instead; the pixies certainly aren’t very helpful.

“What do you mean, we’re not very helpful?” Thistle says. “Look at your code. You haven’t written anything that isn’t needed by something else, so there’s less code to maintain. Because we jump in all the time to try and do jobs for you, every time you can assign a new responsibility to something else, you do - that’s the single responsibility principle in action; none of your classes are doing too much. And you can replace us with something else that does the job at any time - that’s the Liskov Substitution principle. The roles we perform are clearly named. It’s been easy to describe the behaviour of each class using mocks to stand in when we’re not there, and the examples are very readable. You can also use them to work out whether your code still works or not, by running them as tests.”

“Okay. I can’t see myself relying on you guys for bigger, enterprise stuff, though.”

“What do you mean?” Thistle looks offended. Oops.

“Well, let’s say that I’ve got a shop, and I need the tills to talk to stock control.”

“Controlling stock? Oh, I’ll do that!” one of the pixies announces excitedly.

“What, all on your own?”

“Well, I’ll probably delegate it to a team, but that’s my responsibility - you don’t need to worry about it. I’ll be there when you need me. Just pretend I’m there for now. How would you like to find me? What kind of stuff are you going to send to me, and what do I need to do with it? What would you like back?”

So I start with something simple - a URL that I’ll use to find Thistle the pixie, some domain objects that I want to send him, and some objects that I’d like back in return. We talk about how to get the information across, whether some of the tills might provide different stock information, how to talk to the claims department about the quality of the goods we’re selling, and whether I’ll be okay if the claims he gives me have more information than I need.

“Hold on,” I say. “You’ve got me playing this game now. I’m not a Claims Department. I’m not going to do the job myself. I’ve got a home to go to!”

“Meh, never mind,” Thistle replies. “I’ll be sitting with this team over here, coding the stock control. We’ll just pretend you’re doing the job; we’ll mock you out for now.”

“How will I know that I’m doing the job correctly?”

“We’ll have to talk to each other occasionally. Is that going to be hard? We’ll write some scenarios over in our team that describe how we’re going to use you.”

“What if I make a mistake?”

“Do you know what mistakes you’re going to make already?”

“No,” I confess. “I’m sure there will be some, though.”

“When you make a mistake, we’ll deal with it at that point. Sound good?”

I think about it. I reckon I could write some code that pretends to be doing the job of the Claims Department and responds correctly to the way they’ve described how they’re going to use me - just for those examples - then I could go home and Thistle would never know. I knock up a quick stub and slip it into the stock control team’s scenarios, then I disappear too, just like the pixies. I figure I’ll start coding a real Claims Department that does a more robust job tomorrow.

When I get back the next morning, all the pixies performing the role of Stock Control have been replaced with code too. The Stock Control team claim that they’ve never even seen them.

I corner Thistle again. “You’re really not very helpful, are you?”

Thistle looks sulky. “Of course we are! Look at your architecture. You’ve got simple messages going back and forth. Your code is very tolerant of extra information, as is the code on this side. You’ve got lovely RESTful URLs, because you were thinking about how you’d like to find us, instead of us providing you with some weird mechanism that doesn’t match exactly what you wanted. We’ve got clean interfaces and APIs. There are no extra columns in your database, because you only replaced exactly what we said we’d do in the first place. You’ve got scenarios to describe how we work together, and at a unit level examples to describe how you’re delegating responsibility to the other pixies. It’s a lovely, maintainable system with a fairly flat cost of change. Isn’t that what you wanted?”

I nod thoughtfully. “I think it would have been easier for me to just write the code instead of going through you all the time.”

“Ah,” says Thistle, “but then you’d have code that was easy to write, instead of code that’s easy to use.”

I think about how they made me fill in the role of the Claims Department. “You never did any of the work, though! I could have done that job myself; put myself in each of those roles and then replaced myself with real code. That would have let me create consumer-driven interfaces just as easily as using you.”

Thistle shrugs. “If that’s what works for you, sure.”

“Won’t people think I’m a bit mad? If I start talking about how I’m personally going to use a particular class, or how I’m offering to do a job for another?”

Thistle looks at me with raised eyebrows, then gestures at all the other pixies clustered around my desk.

“I think it’s a little late to be worrying about that now,” he says.

This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Wednesday 6-30-04



Things got much better today. Much to my embarrassment, I drove the keyboard for a few hours. I'm slow, I can't type very well, I don't know IntelliJ (the slick Integrated Development Environment (IDE) that Object Mentor uses for writing Java code), but I banged out a few tests and made 'em pass. The problem we were having is that you can attach files to wiki pages in the Old OMwiki. But in the new, FitNesse-centric, wiki we want to put all the files in one area and have links on the pages. This is mostly just a matter of changing the file structure, but it does have the added advantage of being able to link to files from more than one wiki page (well, you could probably do that in the old wiki, but solution would be inelegant). So we wrote a program that checks the folder (of the wiki page) for files and then creates a link to them at the bottom of the page. And it worked.



Mostly.



Some of the files had spaces in them which made our wiki widgets quit while only part of the way through the file name. But, in the plus column, we were able to completely transfer over all the wiki pages and have them look pretty much the same. Right now Paul and I are working on a program to grab all the filenames with spaces in them and cut out the spaces.



The eighties music was off today (which is good because I was getting a little tired of 'Tainted Love') , and Paul played some Beatles on his desktop-sized laptop.



"The eighties music was off today" -- huh? I don't remember this at all. Were the Object Mentors crazed 80s fanatics?



I'm still scared about pairing with people I don't know, oddly enough. I've been doing this pairing thing for 5 years now and yet I still get wound up at the prospect of sharing a computer with another programmer -- what if they're better than me and I feel bad? Almost 100% of the time my fear is completely unfounded and I end up having a great time and learning a bunch. The only time I really hated it is when I let the other person type too much -- then I just feel like a loser. No matter what the skill difference, each pair should spend about the same amount of time driving.
Proposition Rotate leadership roles in agile teams often. Background I’ve been a proponent of flat organisational structures since my time at Thoughtworks.  It’s especially great at promoting communication between all staff. It empowers.  It’s great for morale.  It promotes healthy debate and ideas creation. In this model the importance of organisational hierarchy is overshadowed by the tiers of employee experience.  [...]
This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Tuesday 6-29-04



Well, I didn't drive today, but I did make some progress toward figuring out what was going on. We built a few custom widgets that would translate wiki text that was problematic (for instance: Putting three single quotes around something ('''something''') makes it appear in bold, and two are italics, so 5 should be both italics and bold, right? Not exactly, the FitNesse wiki was only catching the first 3 single quotes. So we used a regular expression (what's a regular expression? A bunch of symbols, which kinda look like swearing ("'''''(.+?)'''''" or ^#[^\r\n]*(?:(?:\r\n)|\n|\r)?), that look for patterns: like a word or words surrounded by five single quotes) to build a custom widget to catch just such a case).



Susan's computer started making this squeaking noise about a week ago. Now it makes a pretty constant background variable squeak/whine. And the parts aren't due in until next week (It's the fan on the processor that's making the noise, so we're a little hesitant to douse it with WD40). Paul sez ignoring it is an exercise in concentration, but I read somewhere that periodic high pitched noises are the hardest to ignore (easiest are low pitch, constant noises).





"I didn't drive today" -- read that as I spent all day watching someone type. Which is not a fun day. Chalk that up to the fact that we were doing regular expressions and I had never seen one before. I'm decent at RegEx's now but I think I avoided them for years because of my first experience. Nothing like resolving to get more involved and then falling out of the frying pan and into the fire to dampen the old spirits. And then a whining computer in the background for extra torment. I'm surprised I didn't just type a single four letter word to sum up June 29th 2004.
One of my colleagues told me the other day: "Szczepan, last year, when I started working in the X team someone warned me not to speak too loud about unit testing" Apparently, there were feisty TDDers in the X team and they witch-hunted devs who not necessarily had written test-first. I guess ...
Just wanted to drop a note that I'll be giving a presentation on Semantic Mashups at the next Chicago Semantic Web User Group meeting in July. Here is the description of the talk:
This month the talk will be given by one of our organizers, Griffin Caprio, on Semantic Mashups.



Description

A mashup is a web page or application that combines data or functionality from two or more external sources to create a new service. Semantic mashups take this a step further by utilizing semantic web technologies to create a richer experience. Using RDF, SPARQL and URIs, mashups can evolve past the simple reuse of data and into the discovery of new knowledge.

In this talk, we'll be presenting sports statistic semantic mashup examples and explaining the underlying techniques and technologies that make them possible.



Speaker Bio

Griffin is a startup oriented entrepreneur with substantial experience in all phases of IT governance, product development and software engineering. Focusing on using technology to solve real problems and reducing friction of how technology affects everyday life, his company, 1530 Technologies, builds well engineered products for real world problems.

We are also scheduling some time for people to meet and talk.

Food and drinks will be provided, however it would be appreciated if you can chip in $5 to help cover our costs.
If you want to come, please RSVP using the links above. That will help us get a idea about food & drinks as well as take care of the building security.

Technorati Tags: , ,



Hi, I'm Michael Chang, the intern that Griffin was talking about. I'm excited to work at 1530 Technologies this summer and get my feet wet in web development. Throughout the summer I will update the blog with what I'm working on as well as any musings I may have about the web or technology in general.

On one last note, Go Lakers!



Release Notes

  • Version 2.0.1 of the test-unit gem introduced a private run_test method on TestCase which clashed with the public TestRunner#run_test method. So this latter method has been renamed to run_as_test.
  • Stop requiring rubygems – this should be an environmental choice for the user. This describes why requiring rubygems in your library code is a bad idea.
  • It seems like overkill to vendorize coderay and meta_project when they’re only needed to generate the examples for documentation and for publishing files on RubyForge. So I’m removing them and installing them locally as gems when I need them.
  • Added support for test-unit gem (version >= 2.0). Note that as with other versions of Test::Unit I’m completely replacing the TestCase#run method. Unfortunately in version 2.0.0 this method differs slightly from the same method in version 2.0.1 & 2.0.2, so we have to provide different implementations to ensure that the internal working of Test::Unit are not compromised by Mocha. Note also that unless the test-unit gem is loaded, requiring 'test/unit' leads to a mixture of standard library and gem classes being loaded causing errors. To avoid a dependency on rubygems, the gem is loaded only if MOCHA_OPTIONS is set to use_test_unit_gem – this option is only intended for use in running Mocha’s own tests. It might be worthwhile to create a shim gem like minitest_tu_shim to allow the test-unit gem to completely replace the standard library, but that’s a job for another day. My previous article on Test::Unit and MiniTest explains how the minitest-tu-shim works. The changes in the Rakefile are to make the default task run with the test-unit gem (version >= 2.0).
  • Renamed Mocha::Standalone to Mocha::API to better reflect its purpose. Added a deprecation warning for those who are referencing Mocha::Standalone.
  • Fix exception raised by HasEntry#matches? when first parameter is not a Hash (thanks to Taylor Barstow).
  • Ken Collins reported that Mocha is always loading MiniTest if it is available and loading it causes some Rails/ActionPack tests to break. I’ve removed the loading of MiniTest, but this now means the user has to ensure that if they want to use MiniTest in conjunction with Mocha, he must load MiniTest before loading Mocha.
  • Implemented Bacon integration (thanks to Ubiratan Pires Alberton), but this was then removed after deciding only to maintain integration with Test::Unit and MiniTest which are both Ruby standard libraries. See mailing list message for details.
  • Don’t monkey-patch MiniTest if it’s already been monkey-patched by Mocha.
  • Fixed bugMiniTest integration was counting ExpectationErrors as errors not failures.
  • Fixed bug – Some Bacon tests were failing in Ruby 1.9.1.
  • Chad Humphries pointed out that in Ruby 1.9.1, if you are not using Test::Unit or MiniTest, Mocha will attempt to load and monkey-patch Test::Unit. Mocha will now only monkey-patch Test::Unit and/or MiniTest if they have already been loaded. MiniTest tests will now run in both Ruby 1.8.6 (with MiniTest gem) and in Ruby 1.9.1 (with MiniTest standard library). See Lighthouse ticket.
  • Made Mocha compatible with minitest 1.4.0 and above (thanks to Denis Defreyne).

Recently I’ve been getting a lot of request for Agile Training and Consulting. Unfortunately the expectations from the training are not clear for me. Most people approach me saying, “we want a TDD training” or “we want a Project Management training“. Once I start talking to them & their team (or even worse sometime during the training), I realize the topic we’re discussing is not their biggest issue. I get a feeling that most organizations have not done their homework to figure out what they really need and how they should go about it. They might have heard somewhere that ‘blah’ will help them and they want to jump on it.

Few months ago I started doing readiness assessments before my trainings. (I’ve also started doing assessments after my training so see if the training was effective.) But I have realized the assessment is not enough. So I’ve started asking the following questions even before the assessments:

  • What kind of issues your organization is facing currently and do you think Agile will help you? If yes, why so?
  • What is the current strength of your development team? How experienced is the team with software development? Does your team understand all aspects of software development?
  • What is the current process you follow? In other words, from the inception of an idea to the delivery of the same, what are the various steps and people involved?
  • What is a day in life of a team member (one per role please)?
  • How do your stakeholders (including customers) perceive your team/organization? Currently how do you gather feedback from them?
  • How would you rate the technical know-how of your team? Are they able to quickly resolve technical challenges and respond to changing priority of the business?
  • Is your team/organization open to trying out things that might seem non-intuitive/illogical? For Ex: Letting the requirements evolve during the project, not freezing them? Letting tests drive your design?
  • And so on …

Luckily a lot of organizations don’t get back to me with answers for these questions. This is really good for me, because this acts as a filtering criteria. I feel I would have wasted my time training/coaching this team. There are others who are in much more need and are more receptive to what I’ve to contribute.

[Post to Twitter] Tweet This Post  [Post to Plurk] Plurk This Post  [Post to Yahoo Buzz] Buzz This Post  [Post to Delicious] Delicious This Post  [Post to Digg] Digg This Post  [Post to Ping.fm] Ping This Post  [Post to Reddit] Reddit This Post  [Post to StumbleUpon] Stumble This Post 

This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Monday 6-28-04



In the morning I installed 40 meg or so of windows 'critical security updates' and after lunch I installed MS Visual Studio. Then I went home.







But seriously folks, that was a fair chunk of my day (2.5 hours alone to install MSVS). Paul and I paired on the OMwiki conversion (to FitNesse) project. I can't say that I'm understanding much. We had this big problem were we couldn't use the 'get' and 'set' methods, but I'm still not sure how we solved it. We did manage to get the conversion program to move all the files to the FitNesse wiki and emulate the FitNesse file structure. But we didn't actually convert the individual pages to FitNesse wiki text yet. I'm so out of it that, when I saw the program run and the files appearing, I thought somehow Paul had finished the conversion right under my nose. I've really got to stop him more often. He understands soooo much more than me I just can't keep up. Micah made a large scale drawing of the program on the whiteboard, but I'm having trouble applying that UML diagram (which I mostly understand, despite my lack of UML training) to the code we are producing. Tomorrow I need to look stupider and feel better about it. This staying quiet and trying guess what's going on isn't working so well.



The funny thing is that, as a teacher, I know that students must take an active role in learning. Which is quite hard if they're way behind. I've seen it before -- when a student gets lost in a class (maybe they missed a few weeks or just took a mental vacation) they tend to shut down instead of asking a lot of stupid questions. Maybe I should drive the keyboard for a while. That ought to be seriously embarrassing.





This is one of about 10 posts where I say something like: "What the hell happened today -- I need to ask more questions." Part of my role at Obtiva is to say this to our apprentices: "Yes I know you feel like a complete idiot and it seems like you can't take one more day of not knowing what the hell is going on, but believe me that I've been there and it will come. Don't be afraid to look stupid early instead of confessing at the end of a week/month/year that you have no idea." Easy to say, but hard to do.



Also the computer I was using was this Dell Inspiron laptop which was about 2 years old at the time and very slow. Installing Microsoft Visual Studio nearly killed it. I think I actually still have it in the other room - I keep meaning to throw it out but it's hard to let go of tech stuff.
This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Friday 6-25-04



We finished the C# class today with an exercise devoted to Threads. In case you have some operation that will take lots of time (like, say, writing to a file) you can send it off on its own while the rest of the program continues on its own way. This is called MultiThreading and it's pretty cool. We designed a thread that scans a directory (folder) every second to see if any text files have been placed in it. If it finds any, it moves them to another folder. We forgot to kill the thread when we were done with it, so the test kept running after we thought it was done. When we tried to manually place some files in the forbidden directory they automatically moved away. Because the cowboys and I are nerds, we created a whole bunch of text files and tired to jam them in the folder before the program could catch up. Alas, the program was too fast for us.



Micah's gonna be gone next week so the apprentices will be on their own.



The really weird thing about that week was that, up until that moment in my life, I truly sucked at puzzles. Somebody would start in with "You and three friends are walking through the forest and each of you has a prime number of hotdogs..." and I'd get lost and start to panic. I'd be thinking that everyone knows the answer to this but me and they are finally going to find out that I'm a fraud and the dumbest guy in the room. So I'd spend most of my thinking time worrying about how much time was left before someone figured it out and then what if they announced that they had got it but didn't tell me the answer and I had to keep thinking about it knowing that someone had beat me to it and it was probably obvious and... Etc., etc., etc.


The weird thing about that week was that I solved every puzzle without getting crazy. It was like after I got the first one I could relax and think about the problem. It's a constant surprise to me how many things essentially boil down to confidence and comfort. If people feel comfortable in a situation they will perform exponentially better than they will in a tense environment.

Fixing a broken build.

I've updated Team Piazza to work with Team City 4.x. You can download the new version at http://team-piazza.googlecode.com/files/piazza-20090625.zip.

I ran across this interesting Scala class by Vaclav Pech which makes the data concurrent rather than the code (if I understood the author correctly). The ~ (extraction) and << (insertion) operators looked nifty.

Looking to do the same in Java, I see four key requirements:

  1. Insertion can happen only once.
  2. Extraction is idempotent (infinitely repeatable, non-modifying).
  3. Extraction blocks until insertion has completed.
  4. Insertion and extraction are both atomic.

With these in mind, I write this:

public class DataFlowReference<T> {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private volatile T item;
    private volatile boolean set = false;
    private volatile boolean called = false;

    public T get()
            throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (true) {
                if (set)
                    return item;

                if (!called) {
                    called = true;
                    onFirstGet();
                    continue;
                }

                condition.await();
            }
        } finally {
            lock.unlock();
        }
    }

    public void setOnce(final T value) {
        lock.lock();
        try {
            if (set)
                return;

            set = true;
            item = value;

            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    protected void onFirstGet() {
    }

    // Object

    @Override
    public boolean equals(final Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        final DataFlowReference that = (DataFlowReference) o;

        return set && item.equals(that.item);
    }

    @Override
    public int hashCode() {
        return set ? item.hashCode() : super.hashCode();
    }

    @Override
    public String toString() {
        return "(" + set + ':' + item + ')';
    }
}

Use of DataFlowReference follows the examples from Vaclav's page: declare dataflow references, create threads whose runables use setOnce() and get(), invoke them all together.

onFirstGet() supports "just in time" supply of item and would call setOnce(T) with a fresh value.

UPDATE: The original version of this class had a horrible, obvious race condition. Caveat plicator.

I’m just reviewing a project’s code. I found a common pattern used in their code base. Every class implements an Interface. Each interface is only implemented by one class. Even more interesting, this interface is not exposed outside. In other words, its not exposed as part of the API.

Then my question is

Why do we need the interface? Why can’t we just use the class directly?

Apparently there is no valid answer. Some told me,

  • Spring forces you to have interfaces.
    • That’s not true.
  • Some told me their mocking framework does not support mocking a class.
    • This is also not true. Most mocking frameworks come with a class extension. Some new frameworks, don’t even distinguish between an interface and a class.

Anyway, we don’t need one stupid interface for every class we create. YAGNI. When we need it, we’ll create it. This is one form of speculative generality code smell.

Go ahead, kill it!

[Post to Twitter] Tweet This Post  [Post to Plurk] Plurk This Post  [Post to Yahoo Buzz] Buzz This Post  [Post to Delicious] Delicious This Post  [Post to Digg] Digg This Post  [Post to Ping.fm] Ping This Post  [Post to Reddit] Reddit This Post  [Post to StumbleUpon] Stumble This Post 

Sahi uses Rhino as its javascript engine and Rhino has excellent support for handling XML.


Below is a script which reads and asserts XML nodes and attributes. The example has been picked from http://www.ibm.com/developerworks/webservices/library/ws-ajax1/ so that it is easy to experiment with the ibm examples in this script.






var xmlStr = '' +

'<people>' +

' <person gender="male">' +

' <name>Ant</name>' +

' <hair>Shaggy</hair>' +

' <eyes>Blue</eyes>' +

' <height measure="metric">176</height>' +

' </person>' +

' <person gender="male">' +

' <name>Paul</name>' +

' <hair>Spiky</hair>' +

' <eyes>Grey</eyes>' +

' <height measure="metric">178</height>' +

' </person>' +

'</people>';



var $x = new XML(xmlStr);

_assertEqual("Ant", $x.person[0].name.toString());

_assertEqual("Grey", $x.person[1].eyes.toString());



for each (var $p in $x.person){

var $measure = $p.height.@measure.toString();

_assert($measure == "metric");

_assert($p.height > 170);

}





Two points to note:
1) All nodes that you access are of type xml. You will need to use toString() on them before you assert them.
2) Using @ from inside a Browser Action Function (like _click, _assert etc.) causes the script to fail because of a parsing error in Sahi's code. So first assign it to a variable and then use it, like it has been used for $measure. This bug will be fixed in the coming release.


There is a lot more that can be done with the XML object. Have a look at these links:


http://www.ibm.com/developerworks/webservices/library/ws-ajax1/
http://www.xml.com/pub/a/2007/11/28/introducing-e4x.html


In Ehcache 1.6, HashMap was replaced with ConcurrentHashmap with statistical sampling for eviction. Having completed 1.6 and released it there were a few surprises along the way with ConcurrentHashMap performance.

PUT and GET performance

There is some existing material online about ConcurrentHashMap versus HashMap performance, notably http://www.informit.com/guides/content.aspx?g=java&seqNum=246. This article finds that ConcurrentHashMap puts are slower than HashMap when the map gets large: for a map of 1 million objects fully population took three times longer than HashMap for a single threaded scenario. However once you get to multi-threaded scenarios, you need to put synchonrization around HashMap. For those few of you in doubt as to this, email me your HashMap usage I will send you back a multi-threaded test that turns your computer into a fan heater (i.e. 100% infinite loop in the CPUs) in about 30 seconds. The cost of synchronization grows as you add concurrency. Put and Get work well with ConcurrentHashMap in multi-threaded scenarios.

Iterate Performance

iterate in ConcurrentHashMap is a lot slower than it is in HashMap and get worse as the map size gets larger. See CacheTest#testConcurrentReadWriteRemoveLFU. For my testing scenarios, which uses 57 threads doing a majority of gets but doing other operations with a variety of map sizes, we get:
      * With iterator:
      * 1.6 with 100,000 store size: puts take 45ms. keySet 7ms
      * 1.6 with 1000,000 store size: puts take 381ms. keySet 7ms
      * 1,000,000 - using FastRandom (j.u.Random was dog slow)
      * INFO: Average Get Time for 2065131 observations: 0.013553619 ms
      * INFO: Average Put Time for 46404 obervations: 0.1605034 ms
      * INFO: Average Remove Time for 20515 obervations: 0.1515964 ms
      * INFO: Average Remove All Time for 0 observations: NaN ms
      * INFO: Average keySet Time for 198 observations: 0.0 ms
      * 9999 - using iterator
      * INFO: Average Get Time for 4305030 observations: 0.006000423 ms
      * INFO: Average Put Time for 3216 obervations: 0.92008704 ms
      * INFO: Average Remove Time for 5294 obervations: 0.048545524 ms
      * INFO: Average Remove All Time for 0 observations: NaN ms
      * INFO: Average keySet Time for 147342 observations: 0.5606073 ms
      * 10001 - using FastRandom
      * INFO: Average Get Time for 4815249 observations: 0.005541354 ms
      * INFO: Average Put Time for 5186 obervations: 0.49826455 ms
      * INFO: Average Remove Time for 129163 obervations: 0.015120429 ms
      * INFO: Average Remove All Time for 0 observations: NaN ms
      * INFO: Average keySet Time for 177342 observations: 0.500733 ms
      * 4999 - using iterator
      * INFO: Average Get Time for 4317409 observations: 0.0061599445 ms
      * INFO: Average Put Time for 2708 obervations: 1.0768094 ms
      * INFO: Average Remove Time for 17664 obervations: 0.11713089 ms
      * INFO: Average Remove All Time for 0 observations: NaN ms
      * INFO: Average keySet Time for 321180 observations: 0.26723954 ms
      * 5001 - using FastRandom
      * INFO: Average Get Time for 3203904 observations: 0.0053447294 ms
      * INFO: Average Put Time for 152905 obervations: 0.056616854 ms
      * INFO: Average Remove Time for 737289 obervations: 0.008854059 ms
      * INFO: Average Remove All Time for 0 observations: NaN ms
      * INFO: Average keySet Time for 272898 observations: 0.3118601 ms
In summary, with 1 million objects in the map a put to Ehcache using iterate for eviction, takes 381ms!

As a result I have used an alternative to iteration using an algorithm called FastRandom. The result is 0.16 ms, 2,300 times faster!

For very small maps, ConcurrentHashMap iteration is quite quick. From experimental testing in Ehcache 1.6 we use iteration up to 5000 entries and FastRandom for sizes above that.

size() performance

Thought not as bad as iteration I have noted size as slow in ConcurrentHashMap compared to HashMap. In Ehcache 1.6 we limit the the usage of size().

Recommendations

If you using ConcurrentHashMap and using more that get/put, test the performance. It may be far, far worse than you were expecting.

To give ConcurrentHashMap the best chance of optimisation remember to set the size and expected concurrency when you create it. In ehcache we set the size to the exact size configured for the cache, and we set concurrency to 100 threads.

Here is a sample of code (happens to be from a test) which I think is not communicative.



public class ContactNumberTest {

  final String exampleCountryCode1 = "91";

  final String exampleCountryCode2 = "1";

  final String exampleNumber1 = "8012345678";

  final String exampleNumber2 = "2028569635";

  

  ContactNumber phoneNumberA = new ContactNumber(exampleCountryCode1,exampleNumber1);

  ContactNumber phoneNumberB = new ContactNumber(exampleCountryCode1,exampleNumber1);

  ContactNumber phoneNumberC = new ContactNumber(exampleCountryCode2,exampleNumber2);

  

  @Test

  public void testEquals() {

    //Symmetry

    assertTrue(phoneNumberA.equals(phoneNumberB));

    assertTrue(phoneNumberB.equals(phoneNumberA));

    

    //Reflexivity

    assertTrue(phoneNumberA.equals(phoneNumberA));

    

    //Not equals

    assertFalse(phoneNumberA.equals(phoneNumberC));

  }

  

  @Test

  public void testHashcode() {

    assertTrue(phoneNumberA.hashCode() == phoneNumberB.hashCode());

  }

}

I know you must be wondering why in the first place someone is writing tests for equals and hashCode. I agree. Its not required. But lets say someone really needs to.

This is how I would refactor the code to make it more communicative.



public class ContactNumberTest {

  private final String indiaCountryCode = "+91";

  private final String usCountryCode = "+1";

  private final String cellNumber = "8012345678";

  private final String mobileNumber = "2028569635";

  

  private final ContactNumber indianNumber = new ContactNumber(indiaCountryCode, cellNumber);

  private final ContactNumber sameIndianNumber = new ContactNumber(indiaCountryCode, cellNumber);

  private final ContactNumber usNumber = new ContactNumber(usCountryCode, mobileNumber);

  private final Map users = new HashMap();

  private String userName;

  

  @Test

  public void isSymmetrical() {

    assertNotSame(indianNumber, sameIndianNumber);

    assertEquals(indianNumber, sameIndianNumber);

    assertEquals(sameIndianNumber, indianNumber);

  }

  

  @Test

  public void isReflexive() {

    assertEquals(indianNumber, indianNumber);

  }

  

  @Test

  public void isTransitive() {

    ContactNumber newIndianNumber = new ContactNumber(indiaCountryCode, cellNumber);

    assertEquals(indianNumber, sameIndianNumber);

    assertEquals(sameIndianNumber, newIndianNumber);

    assertEquals(newIndianNumber, indianNumber);

  }

  

  @Test

  public void areNotAlwaysEqual() {

    assertFalse(indianNumber.equals(usNumber));

  }

  

  @Test

  public void equalsIsExceptionFree() {

    assertFalse(indianNumber.equals(null));

  }

  

  @Test

  public void isHashFriendly() {

    addUser(”Foo”).usingKey(indianNumber);

    assertEquals(”Foo”, users.get(indianNumber));

    addUser(”Bar”).usingKey(sameIndianNumber);

    assertEquals(1, users.size());

  }

  

  private void usingKey(final ContactNumber number) {

    users.put(number, userName);

  }

  

  private ContactNumberTest addUser(final String userName) {

    this.userName = userName;

    return this;

  }

}

[Post to Twitter] Tweet This Post  [Post to Plurk] Plurk This Post  [Post to Yahoo Buzz] Buzz This Post  [Post to Delicious] Delicious This Post  [Post to Digg] Digg This Post  [Post to Ping.fm] Ping This Post  [Post to Reddit] Reddit This Post  [Post to StumbleUpon] Stumble This Post 

At SpeakerConf 2009, one of the speaker's wives asked me: Why is it that most speakers are confident, and some are simply arrogant. The question was also in the context of "software is nerdy, how can you speakers be so cocky". I pondered for a minute and replied: When no one knows what's "correct", people with confidence generally win the discussion.



Imagine the early days of medicine. Three different doctors give you three different surgery options. There's not enough experience in the industry to show which is the correct choice. Who do you trust? Probably the doctor who managed to be the most confident without being overly aggressive or cocky.



As I've said before, we're still figuring this stuff out. I constantly try to improve my processes for delivering software. I share those processes via speaking and blogging. However, I'm definitely aware that I could be doing it entirely wrong.



In general, I'm weary of developers who speak in absolutes. Most solutions I've seen are contextual, and even in context they tend to be fragile. We simply don't have the heuristics to determine what true best practices (for our field) are.



When pondering the original question I remembered when I wrote about Despised Software Luminaries. At the time I blamed passion; however, I'm guessing confidence and arrogance probably also weigh heavily on the source of animosity.



There's a direct correlation between being a luminary and your compensation package. Therefore, luminaries are enticed to gain as much market share as possible. Your luminary status is determined by the speed at which your ideas are adopted. And, without absolute proof of correctness, the speed at which your ideas are adopted can largely based on your confidence. I'm sure some luminaries see this situation and walk the line between confidence and arrogance.



Of course, not all luminaries are in it for compensation. I truly doubt Martin Fowler does what he does for money. But, the people who are looking to take market share from Martin may be motivated by a compensation package. Therefore, it's pretty hard to escape the the effects of confidence and arrogance.



The confidence and arrogance discussion is also interesting if you've ever met a luminary who you found to be completely incompetent. Perhaps they truly don't know what they were talking about, and they've just been confident enough to fool the majority of people they've met so far.
This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Thursday 6-24-04



You Cowboy has taken to saying 'sankyou' when Cowboy helps him out. Cowboy replies with an even more Asianized 'sankyou' and we move on. You Cowboy is also fond of saying 'RefRactor' and 'Ohh Cowboy'' (with this sort of world-weary sigh that's just perfect) There were times when I couldn't code because I was laughing so hard. A quality experience.



The pattern that established itself is this: Micah introduces some concept in C#, such as event handling, and we stare at him confusedly. Then we do a project involving said concept. I get really confused, while the Cowboys trade barbs. Eventually we figure it out. And Cowboy checks his eTrade account. Repeat cycle.



Incidentally, 'delegates' are really cool. They are methods that you can pass around. I have this problem in my Tic Tac Toe game where I keep having to cycle through all the spaces in the board. So my code is littered with things like this:



for( int row = 0; row < 3 ; row++)

{

for(int column = 0; column < 3 ; column++)

{

[[some function or other]]

}

}



The functions in the middle do all sorts of different things. I think that with a delegate I might be able to have just one place where that nested 'for' loop happens, but with an assignable method inside. Which would be cool. Except that TTT is written in Java and delegates are in C#. Micah thinks that using 'runable' will work, but David thinks it'll be tricky (David thinks it'd be a snap to do in Python -- always with the Python). Anyway, I'm gonna try.



When pairing goes well it's like hanging out with your friends all day, getting work done, and getting paid to do it.



To be totally honest I never did try to use Python or 'runable' to solve the TicTacToe repeated code problem. I did later learn Ruby and blocks which solved the problem quite nicely. As my friend Pat Farley once said: "Ruby is great at removing the duplication where you're doing the exact same thing repeatedly but all the words are different." I had to think about that one for a week before I got it.
Eclipse's JSDT plugin provides syntax highlighting and verification for Javascript. It can be configured to work well with Sahi scripts too. This video goes through the different steps to configure Eclipse to work with Sahi scripts.




JSDT looks at all functions in the given source folder and can list them in content-assist. Taking advantage of this, we use a dummy definitions file called apis.sah which has all the Sahi APIs. This file, apis.sah, can be downloaded from here and needs to copied into the "scripts" folder.


JSDT is a part of the Web Platforms Toolkit.
It can be installed as a plugin or can be downloaded as a single bundle in the "Eclipse IDE for Java EE Developers (163 MB)" (For windows: eclipse-jee-ganymede-SR2-win32.zip). This is downloadable from http://www.eclipse.org/downloads/


I've noticed a pattern pop up a few times in my Java code in the past 6 months. Maybe it's a decent pattern, or maybe I only have a hammer.



The problem I'm trying to solve is setting some global state, running a test, and ensuring that the global state is set back to it's original (or correct) value. My usual solution to this problem is to remove global state, but not all global states are created equally. The two global states I've been unsuccessful at removing are the current time and system properties.



In my previous post I described how I freeze time using the Joda library. The example code for freezing time was the first time I used a Method Chain with a Snippet. At the time I thought it was an ugly solution, but the best I could come up with.



A few months later I was testing some code that set and read from the system properties. My first tests set the properties and didn't clean up after themselves. This quickly caused trouble, and I found myself turning to Method Chain with Snippet again.



Here's some example code where I verify that setupDir doesn't overwrite a default property:



@Test

public void shouldNotOverrideDir() {

new Temporarily().setProperty("a.dir", "was.preset").when(new Snippet() {{

new Main().setupDir();

assertEquals("was.preset", System.getProperty("a.dir"));

}});

}



And, here's the code for the Temporarily class



public class Temporarily {

private Map properties = new HashMap();



public void when(Snippet snippet) {

for (Map.Entry entry : properties.entrySet()) {

System.setProperty(entry.getKey(), entry.getValue());

}

}



public Temporarily setProperty(String propertyName, String propertyValue) {

if (System.getProperty(propertyName) != null) {

properties.put(propertyName, System.getProperty(propertyName));

}

System.setProperty(propertyName, propertyValue);

return this;

}

}



The code works by setting the desired state for the test, chaining the state cleanup method, and passing the test code as a Snippet to the state cleanup method. The code exploits the fact that Java will execute the first method, then the argument to the chained method, then the chained method.



For the previous example, the 'setProperty' method is executed, then the Snippet is constructed and the initializer is immediately executed, then the 'when' method is executed. The Snippet argument isn't used within the when method; therefore, no state needs to be captured in the Snippet's initializer.



This pattern seems to work well whenever you need to set some state before and after a test runs. However, as I previously mentioned, it's much better if you can simply remove the state dependency from your test.
This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Wednesday 6-23-04



More fun today with 'Cowboy' and 'You Cowboy.'



We got to a point where I was totally lost. Finally. Monday and Tuesday were all about picking up small things and differences from Java. Today we got into some full on Polymorphism and it was cool/confusing. Cowboy and You Cowboy were all over it and, unfortunately, I was driving (had control of the keyboard). Cowboy started talking a mile a minute while You Cowboy had some helpful suggestions about topics unrelated. I had just about no idea what I was typing. I don't think pair programming works very well with 'pairs' of three -- sometimes there is too much going on and rational thought is impeded. Later I was able to catch on and here's what was happening: The CheckBook can take in Deposits and Checks, both of which are children of the Transaction class. Today's big task (amongst others) was to give the CheckBook class the ability to step through all the transactions and reorder them. That meant the CheckBook had to inherit from the Enumerator class and the Check class needed to inherit from Enumeratable. And there was much Overriding and passing of classes and the casting -- don't forget the casting. In fact, just thinking about it makes me want to look over the code again. I've got to get M.S. Visual Studio installed on my laptop. Instead, I've been having fun using OM's super-fast mini-computers. They have these cute little Dells with flat panel screens that can fit four to a box in shipping crates. Pretty handy if you need to haul a bunch of computers to a conference (like, say, the XP/Agile Universe conference August 15-18 in Calgary! Whoo!).



I got another puzzle right today. What's up with that? If you want, here it is: You are in a room with three switches. In another room, not visible from your room, are three lights. Each light is controlled by one switch. All the switches are off now. If you leave the room to check on the lights, you can't come back (the door locks behind you, poison gas steams into the room, dogs are released that shoot killer bees out of their mouths when they bark, etc.). You can play with the switches as long as you like but when you go to the other room you want to be able to know which switch controls which light.



Remember: Penn and Teller say that people who love puzzles must die.



Oh 'Cowboy' and 'You Cowboy!', your antics still amuse after all these years. Not so pleasant memories about casting classes into other classes. That whole statically typed thing seems like such a fad in hindsight. I shouldn't really trash talk about Java and C# though. I think half the reason I react with aversion to them is that I was a mediocre programmer back when I was in static land. When I was in Ruby I really came into my own as a programmer and so I associate Java and C# with the times in my life when I sucked and Ruby with some actual competency and satisfaction.

Also, I love the part where I was impressed with the flat panel monitors -- this was 2004 when only the serious would shell out tall green for a 15 inch monitor with thousands of colors and a 1:50 contrast ratio.

Here's a pretty good explanation of call/cc.

Once upon a time Mark Needham wrote about freezing Joda Time. Mark gives all the important details for freezing time (which is often helpful for testing), but I came up with some additional code that I like to add on top of his example.



Two things bother me about Mark's example. First of all, I always like the last line of my test to be the assertion. It's not a law, but it is a guideline I like to follow. Secondly, I don't like having to remember that I need to reset the time back to following the system clock.



I came up with the following idea. It's definitely a poor man's closure, but it does the job for me.

    

@Test

public void shouldFreezeTime() {

Freeze.timeAt("2008-09-04").thawAfter(new Snippet() {{

assertEquals(new DateTime(2008, 9, 4, 1, 0, 0, 0), new DateTime());

}});

}



The Freeze class is very simple:



public class Freeze {



public static Freeze timeAt(String dateTimeString) {

DateTimeUtils.setCurrentMillisFixed(JodaDateTime.create(dateTimeString).getMillis());

return new Freeze();

}



public void thawAfter(Snippet snippet) {

DateTimeUtils.setCurrentMillisSystem();

}

}



The Snippet class is even more simple:



public class Snippet {}



Using this code I can keep my assertions as close to the end of the test method as possible, and it's not possible to forget to reset the time back to the system clock.

@Directi we are committed to improve the technical community in India. We started off with TechCamp. Next we launched CodeChef. And now we proudly present DesignChef.

Unlike CodeChef, which was targted at Developers, DesignChef is targeted at Design Professionals like Usability Experts, UX Specialists, Interaction Designers, Front-end developers, etc.

We welcome you to join this non-profit, community initiative and help us grow it.

[Post to Twitter] Tweet This Post  [Post to Plurk] Plurk This Post  [Post to Yahoo Buzz] Buzz This Post  [Post to Delicious] Delicious This Post  [Post to Digg] Digg This Post  [Post to Ping.fm] Ping This Post  [Post to Reddit] Reddit This Post  [Post to StumbleUpon] Stumble This Post 

This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Tuesday 6-22-04



More C# today. I was working with two paying customers: Tony and Jeff. Watching those two bounce off each other was a riot. Jeff kept wanting Tony to type faster and Tony got even with Jeff by adopting an Asian accent (Jeff's Asian). Jeff wasn't super impressed with either TDD or refactoring so he kept advocating shortcuts, but Tony kept telling him to slow down 'Cowboy.' Why 'cowboy,' I don't know but it was pretty funny.



We wrote a checkbook program today and we got to use polymorphism. A checkbook can take in deposits or checks, but both are really transactions. So we wrote an abstract Transaction class and then had the Check and Deposit classes inherit from it. It passed the tests, but I need to look it over because by the end of the day we had given in to Jeff's demands and started just doing what he said. Things went kinda fast after that.



In the category of strange but true: I solved not one but two puzzles today. Normally I end up visualizing the person who offers the puzzle as a more gasoline soaked combustible version of themselves. But today things were different.



You should stop reading now if you don't like puzzles. You have two lengths of rope that will each take 60 seconds to burn. The rate of burning, however, is not constant. So one rope may burn through 90% of it's length in 5 seconds and take 55 seconds to consume the other 5%. The ropes are not identical. While one may do 90% in 5 seconds, the other may do the first 90% in 40 seconds. The only thing that is sure is that each will take 60 seconds to burn all the way. You have a box of matches, but no access to a timer. Your goal is to use the ropes to measure 15 seconds.



Fun fact: The two guys worked at a place in my old neighborhood where I got arrested and thrown into jail. Lemme give you some advice about getting arrested -- always carry 100 dollars on you in cash so you can bail yourself out. Most non-terrible offenses have a thousand dollar bail, but they'll accept 10%. The 'jail' was a bit of a let-down as it was really just a room with a locked door and a pay phone. On the plus side I got to call my Dad from 'jail.' Remember that old 'Was not was' song 'Hello dad, I'm in Jail'? Well I do.

As I start working here at 1530 Technologies, I'm starting to see just how important it is to keep usability in mind.

For example, the registration process can make or break any web application. If there are too many steps involved in getting registered and if the user is not dead-set on the product, they may lose interest. I implemented two such usability improvements on one of the apps we're working on:

  • If a user has already registered to use our service and they are not logged in, he'll see the initial information/sign-up page. If the user inputs his name into the email sign-up form, he will be redirected to the login form with the login already filled in. This helps to reduce the amount of clicking and typing that a registered user has to go through to access the web application.
  • When a user signs up, they receive an email with a link to activate their account. Clicking on the activation link in an email will activate their account, but it will also log them in immediately (instead of having to log in manually). If a user has just activated via that unique activation url, it makes sense to automatically log him in. This also reduces mouse-clicks, typing, and time (that the user needs to look for the login form.

Given my limited knowledge, I think these are simple usability tweaks that anybody could integrate into their page. Good Luck!



This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Monday 6-21-04



Long bike ride in the rain this morning. Only got scary when those 16 wheelers zoomed by throwing a few gallons of water at me and my wiener bike. Micah was teaching the C# class today and lots of it was familiar b/c Java and C# are pretty darn similar, but it was cool to review TDD best practices while working with someone who didn't know about 'em. I was paired up with one of the paying customers ('Tony') and we managed to figure out M.S. Visual Studio. It's kinda like FrontPage in that it tries to force you to do things the Microsoft way. The refactoring tools are pretty crappy -- no extract method option (which is my new favorite thing)! So Tony and I had to do our own refactoring which was a good exercise. C# does have a cool decimal class which gives you arbitrary precision up to 26 places. This is very cool for money programs, because, as we all know, that guy (Richard Pryor) in that Superman movie used the rounding errors to steal money from banks and we can't have that. Anyway, I feel like C# isn't going to be to hard a transition, but it should be said that today was only the beginning.



I was sleepy all day today because we had this late-night cast party at my pad this weekend. Laura's cast came over and brought their friends. All in all it was about 25 people. I'm glad my landlord (who lives below me) wasn't home because there was lots of loud music and dancing. Right in the middle of Micah's lecture he looked over at me and caught me in this huge yawn -- for the record it was the sleep deprivation and not the class.



In Tic Tac Toe news: My program is now passing 11 out of 11 tests! And the methods tested include minimax and makeTheComputerMove. Now all I gotta do is figure out how to test the human interface. Hmmm.



Yeah that bike ride was kind of a harrowing adventure each morning. The only road that went directly to Object Mentor was a four laner that got lots of traffic. Could be pretty scary.
Can anyone recommend a good programmer's editor for Mac OS X?



It must be free, that rules TextMate out.



It must have source code editing features (syntax highlighting etc.), and be able to cope with long files (GBytes).



So far I've been using JEdit which is otherwise quite good but its MacOS integration is quite flaky due to the fact that JEdit is written in Java and thus it depends on Apple's Cocoa-Java integration API which changes all the time. Also, JEdit is not very good with long files since it tries to load the whole file into memory (i.e. JVM heap).



I have tried TextWrangler but I didn't like it very much. I'm also not a big vi fan.



Any ideas?



PS. Obviously the GB long files are not source code ;-)

Till a year ago, I used to think of command & control as micro-management. Last year I heard Mary Poppendieck give a different perspective about it in her keynote(pdf). That’s when I realized that Command & Control means quite opposite of micro-management.

We all know Command and Control comes from US Army. During wars, the Commanders would direct (command) the troops on ground about the next move (goal/mission). And then the staff (troops) on ground would figure out the best strategy to achieve the mission. This is very different from micro-management.

Once the Commanders gives the commands, there is no way s/he can control the situation on ground. Tactical decisions are made by the staff on the war field and strategic decisions are made by Commanders and others outside the war fields, based on their knowledge about situation on the ground.

(no plan survives contact with the real enemy).

The heart of mission command:

Commanders should issue only the most essential orders. These provide general instructions outlining the principal objective and specific missions. Tactical details are left to subordinates.

“The advantage which a commander thinks he can attain through continued personal intervention is largely illusory.”

http://www.dtic.mil/dticasd/sbir/sbir043/a30a.pdf

[Post to Twitter] Tweet This Post  [Post to Plurk] Plurk This Post  [Post to Yahoo Buzz] Buzz This Post  [Post to Delicious] Delicious This Post  [Post to Digg] Digg This Post  [Post to Ping.fm] Ping This Post  [Post to Reddit] Reddit This Post  [Post to StumbleUpon] Stumble This Post 

Have you ever heard (or said) something like "you've got to work [long hours/weekends] because the customer has been promised [some system/feature] by [some date]"?



Commitments can be made but not assigned



People only feel committed to things they have committed to themselves. Telling someone that they have to work long hours/weekends because of a commitment someone else has made can lead to demotivation and resentment. Productivity is very likely to suffer (quality decreasing, more rework due to mistakes, more stupid things done due to rushing or tiredness). Seeing that the work isn't being completed quickly enough, bad managers think that it just requires even more hours to be put in (they try to impose "more commitment" and concentrate on the inputs rather than the outputs). This is the recipe for a "death march" project.



Estimates are not commitments



As a project manager, you have to understand the difference between an estimate and a quote. An estimate is not a commitment. As a project manager, if you make a commitment that something will be done by a certain date then do not rely on being able to just use estimates directly - you need to apply some project management techniques. One technique that I have found works well, as mentioned in my previous article is "extreme planning".



Commitment can work wonders




When someone really feels committed to something, then they will be motivated and focused. Software developers will often work harder and more effectively on their pet open source project than they do at work due to this motivation. This sort of commitment cannot be forced onto someone. There are lots of ways to ensure it doesn't happen (sadly common) and a few things you can do to provide an environment in which it might happen - and hence see massive improvements in productivity and quality as a result.



One factor is the level of technical autonomy. Many large companies have standards which are intended to reduce costs (for various reasons I won't go into). Unfortunately, I think in many cases these standards tend to reduce teams' technical autonomy, which reduces motivation, having a larger negative effect on productivity (hence cost) than the savings made by the standardization. I'm thinking of things like (for example) being told you have to use Wholly Pointless Server when some free open source app server would be a better choice.



Another factor which I think is very important is how directly developers work with their customers. A lot of developers (and certainly the ones I like working with) like to do things which are useful and appreciated by the users of their software. Sometimes the way teams are set up there is a separation between developers and customers - often a business analyst who understands the business and is more available than the real customer(s). This does have benefits when a developer wants a question answered straight away (but the customer isn't available), because otherwise the developer would be blocked or have to context switch onto another area of work. However, I think the best arrangement (not always possible) is when the real customer is available all the time and the developers talk directly to them. The worst situation is when only the project manager or business analyst talks to the customer and approaches the developers with an attitude of demanding features rather than working collaboratively for the best solution.



There are lots of other factors involved in motivation - I might write more in a future article - if I can be bothered. :-)



Bike ride commitment



As an example of commitment - I said I'd do the London to Aachen bike ride and people sponsored me to do it (many thanks), so I felt a commitment to do it. If I hadn't felt any commitment then I wouldn't have done it because, frankly, it wasn't much fun. Here's a quick summary of how it turned out:



Day 1 - Gatwick to Dover/Dunkerque (85 miles cycling) - it wasn't too bad - a bit of drizzle, nice scenery and the cycling was not too tough. (We then got a ferry to Dunkerque - the staff at Norfolk line ferries were great, putting on a fantastic meal, and a tour of the bridge, specially for us).



Day 2 - Dunkerque to Waterloo (139 miles) - we had an early start (breakfast at 6:30am local time, i.e. 5:30am UK time) - in order to do 70 miles before lunch - the roads were totally flat but it was into a headwind the whole way - it was brutal. Some participants skipped the afternoon cycling and got a minivan to the hotel straight after lunch. Immediately before lunch I felt like going in the van too, but after some food felt much better and thought I'd try to keep going. The afternoon turned out to be much better - it was a bit hilly but much less windy. At around 100 miles for the day, 3 other particpants dropped out and got in the support van. At around 120 miles for the day I was knackered - but just about managed to finish the day's ride - going really slowly for the last 20 miles.



Day 3 - Waterloo to Aachen (106 miles) - I was knackered from the day before - so I took it very easy, along with some of the others who had struggled to complete the previous day's ride. There were some cobbled roads, which on a race bike are very scary. Near the end of the day, going up a long climb (which features in the pro cycling "Amstel Gold" race), we cycled through a thunder storm - we had hail, torrential rain (consequently very bad visibility), thunderbolts and lightning (very very frightening).



Copyright © 2009 Ivan Moore
This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Friday 6-18-04



I arrived this morning to find that the Martins are back in town. Bob seems like a good guy. I didn't talk to him much, but working next to someone all day can give you a good impression of a person and Bob seemed easygoing and fun. He also was trying to quote some obscure line from a classic Star Trek episode (you know the one where the crew of the Enterprise have been captured by an alien being (again) who wants to learn about humanity (as always) by having them play out some bit of 19th or 20th century history (this time it was the shootout at the OK coral)? Well, I do.) so that gets put in the plus column. Micah took a look at our project. Then he asked us what we thought the project was.



Uh oh.



'Er, to change the OMwiki python code so that it operates more like the FitNess wiki?' Well, not really, as it turns out. What he really wanted was for us to translate the OMwiki pages into FitNess wiki pages so they could kill off the old OMwiki and have it be re-born with all the added features of the FitNess wiki. 'Oh.' We said.



So we start over.



One very cool thing about today is that Micah offered to let me sit in on the C# course that he's teaching next week. I was worried that I might slow the class down because I'm an absolute beginner (I know it's a Java knock-off, and that's about it), but that's who the class is for. Excellent.



Paul and I started writing the wiki conversion program -- TDD style of course. There will be no coding without a failing test. After a few days of Python's super easy file writing techniques, we had to stumble around with Java's roll your own types. Basically, Python is a higher level language than Java so it does a lot more for you. Yes, I grudgingly admit that Python has advantages over Java -- There, I've said it.



When I first started re-reading these blogs post I thought to myself: "Funny, I don't remember that we spent a lot of time fixing up the old Python wiki..." Yeah, that's because we didn't -- We burned a week working on the wrong project. I felt so stupid. However, it's an important point that when XPer's start going on and on about having an onsite (or highly available) customer you should probably listen. I've seen this situation many times since: Only person who knows what they want is totally unavailable and so the developers work on their own only to realize that they totally misunderstood the requirements. The awesome thing is that Object Mentor makes its living teaching people how to be Agile/XP and they still made the classic off-site customer mistake. This isn't to bash on them, but merely to say that when the major stakeholders are unavailable (or perceived to be so) then you're going to waste a lot of development time.



Also, Uncle Bob is a nerd's nerd. One time someone was using an old-school dial up modem in the office while he was around. Just from listening to the "scree scraa scraa" noises it made, which he casually heard from across the room while working on something else, he diagnosed some problem or other.
I went to the first ever ORD session last night sponsored by Inventables and Google Chicago and worked on some metric_fu stuff. The idea of the ORD sessions is that there's a lot of open source developers in the Chicago (ORD is the O'Hare airport code) area so why not get them together to hack on some stuff. I'd say over 20 people showed up and had a great time. It didn't hurt that every one who came got an unlocked google phone as a free surprise gift. When they announced, earlier in the evening, that there would be a surprise we all thought: "Oh cool, I'll probably get a t-shirt or a squishy ball." So the phone sort of blew us away.


As to metric_fu, Jeff from Inventables and I paired on a new meta metric called "Flurn." It's a combination of FLog and chURN and it tells you about files that not only are very complex but also change all the time. This is pretty bad because if the file is in constant flux and it's got a lot of convoluted code then that's a bunch of bugs waiting to happen.


"Flurn" is available through the appropriately named 'flurn' branch of metric_fu on github if you want to check it out before it's released in a future version of metric_fu.


Speaking of future versions of metric_fu, there should be one coming out soon with 'awesome' templates and graphs of metrics over time. Stay tuned.



I am seriously impressed with Amazon's cloud offering. You get a pick list of virtual machines of different sizes, a CDN, monitoring with elastic forking of new instances, fixed IPs if required, S3, attachable storage and the ability to release software as .amis for easy deployment, map-reduce with Hadoop, load balancing and a payment service.

Each of these is configurable via a RESTful web service. Each one has command-line tools that interact with the web services which you can easily script. And I can see that the new https://console.aws.amazon.com management console will bring this together into an easy to use package. Right now there is a tab for EC2 and another for Map-Reduce. Give it a few more months and I can see this populated with tabs for the other services.

Ehcache Server AMI

I love EC2 so much that I decided to create an Amazon Machine Image (AMI) for Ehcache Server. It is marked public and is available for anyone to use. I see it being used in two ways:
  • To quickly try out and demo Ehcache Server. If you have an EC2 account you can be up and running in less than a minute.
  • As an example of how to deploy Ehcache Server. The AMI comes with an init.d script for service control and ipchains rules mapping ports 80 and 81. You can use it as a template to create your own AMI with your own cache configuration.

Getting Started

  1. Create a new virtual machine. Select ami-3512f45c from the Community AMIs tab. Select a security configuration and a machine size (small is fine) and start it up. Ehcache Server will start automatically.
  2. To test it, hit it with http://amazon_instance_address/ehcache/rest/sampleCache1. From there, try writing a client. See the Cache Server documentation for sample client code in several languages.
  3. To make configuration changes log into your machine. Ehcache Server is insatalled in /root/ehcache-server-0.7.

Video Tutorial

I have put all this in a video tutorial.
As I've announced elsewhere earlier this month, Pete Dignan and I are shutting down WatirCraft LLC. We've each decided to go our separate ways. For several months now Pete has been focussing his attentions on his other business, ProtoTest. Next...

No, it's not.

My team has been recently tweaking our daily ceremonies. Once upon a time we had a combination of standup and huddle.  Standup being the usual brief on yesterday and todays focus and blockers.  Huddle being the team gathering around the story wall and discussing progress and issues in depth. We eventually acknowledged the overlap between the two [...]
This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Thursday 6-17-04



You know what? I had fun today. Imagine that. Yes, some of the day was spent looking at the OMwiki pyhton code which still confuses the hell out of me, but I learned how to extract methods in Eclipse. I know I'm not the first person to say this but, the 'extract method' thingy is way cool. It makes it sooo easy to slice large pieces of crazy code into much smaller, friendly, bits. Almost fully automated creation of methods. Neato.



The other fun thing I did today was getting my Python Tic Tac Toe to not only run, but to play perfect. It takes forever, though. David and Paul say it shouldn't take that much longer than Java, but it does. If the TTT board is empty, it takes about a minute to make a move.



Yet more fun, I'm doing a TDD (Test Driven Design) re-write of Tic Tac Toe in Java. I've hidden the original code away and I'm writing the tests first using the Junit plug-in (this program works with Eclipse to make running tests easy). When your test passes, you get a green bar. Failure is red. It's amazing how addicted you can get to seeing that green bar.



Humbling moment of the day: I'm eating lunch with Paul and I'm describing my Tic Tac Toe program. Somewhere in the conversation he casually mentions that He, Micah, and Chris (former OM employee) each wrote their own chess programs awhile ago. For fun.



Yipes!



If you don't play chess, lemme tell you: It's scary complex. It took Paul six months. Paul's actually been working for OM for about 4 years now. He spent the first 1.5 years working year round when not at school. But then he settled into just working when he's off school. Paul's thinking of getting a Master's in Math.

No Micah today, but he should be in tomorrow. Paul has made some good progress on the OMwiki widgets so I feel much better about the project than I did Monday or Tuesday.



Writing a chess program for fun -- still blows my mind. I believe they had their chess programs play each other. I aspire to someday be that geeky.



There was a time I thought I would never go back to a non-refactoring IDE, but I've been using TextMate for a few years now. Although, one of the guys at work uses RubyMine and I have to say that it's coming along quite nicely. I've had my heart broken with Ruby IDEs so many times in the past that I don't know if I'll ever love again.

I'm running a give-away on my other blog. Atlassian are giving away a license for the Bamboo Continuous Integration server. There's also 10 Bamboo T-shirts up for grabs. Just write a few paragraphs about your best or worst build experiences ...

http://www.build-doctor.com/2009/06/16/atlassian-bamboo-giveaway



This summer I'm revisiting my short apprenticeship at Object Mentor. I'll be posting commentary on all my posts from the summer of 2004 exactly 5 years later to the day.


Wednesday 6-16-04



The first part of the day was more crazy python code. I was asking Paul some more questions about the Visitor pattern and at some point, while he was describing some aspect or another, he said 'It's kinda like a linked-list.'



This happens a lot. Somebody at OM explains some complicated thing with another complicated thing and I have to take a deep breath and say 'So, what is a linked-list?' At which point paper comes out and drawings are made and I realize that I hadn't really understood arrays until then. I'm so behind the curve in terminology it can be overwhelming. But, I should add, this is a thousand times better than being bored in my Java class. From way too slow to way too fast in one month.



Total immersion is supposed to be a good way to learn a language. I hope so.



We (and when I say we, I mean 95% Paul) did make some good progress on the OMwiki widgets. We've got the widgets successfully passing 5 or so tests. But the wikiWord widget is giving us problems for reasons I don't understand. Something to do with a class/method we can't call from where we are.



I, however, finally got my Tic Tac Toe to program to run without giving me some crazy sort of error. Whoo! That success was tempered by the realization that the program now plays very poorly. Wha happen? One of the big problems turned out to be Pythons' way of sending the object as an argument (the infamous 'self') We ran into that problem a lot in our OMwiki project. Many methods have to take in self and then, to address one of the object's variables, you have to write self.myVariable instead just saying myVariable.



On the way to the train today my bike's gear shifter wire slipped out and the bike defaulted to 3rd gear. Hills became interesting after that. The good people at Rapid Transit (Excellent bike shop) fixed it in 5 minutes for free! Everybody reading this (all 5 of you) should go buy something from them right now (corner of Wolcott and North in Chicago). Later, Bryn and Tina came over to my pad and we indulged in some drunken video game funness (in the interests of full disclosure, we played: 'The Simpsons: Hit and Run.' You know that one level, where you have to use the Globex Supervillain car to demolish all the free laser gun stands, and then get back to KrustyLu studios before time runs out? That's the level we couldn't beat.)



"The Simpsons: Hit and Run" is/was one of those truly great games I still think about from time to time. I wonder if I still have it... Damn! I must have sold it when I got rid of my original Xbox to that guy I met though Craigslist -- he was buying the Xbox and most of my games for his 7 year old son. Only later did it occur to me that I had a number of Grand Theft Auto titles mixed into that bundle. Oh well, that kid's gotta learn about graphic violence someday.



The 'Linked-list' moment still stands out in my brain because just before telling me "It's kinda like a linked-list," Paul had this great look on his face like he had finally thought of a super easy way to explain this concept. He was so clearly pleased with his analogy that I felt just awful fessing up that I had no idea what he was talking about. The weird thing was that, as a teacher, I was totally used to this situation -- just on the opposite side of the learning curve. But that was my job that summer: To get my mental ass kicked every day, learn from it, and come back for more.

My tour of functional programming idioms in C# 3.0 continues with some continuation tests. These two tests are equivalent:

[Test]
public void ExplicitReturnStyle()
{
    Assert.That(someObject.Identity("foo"), Is.EqualTo("foo"));
}

[Test]
public void ContinuationPassingStyle()
{
    someObject.Identity("foo", s => Assert.That(s, Is.EqualTo("foo")));
}

Given these two overrides of Identity:

public T Identity<T>(T foo)
{
    return foo;
}

public void Identity<T>(T foo, Action<T> f)
{
    f(foo);
}

In the Continuation Passing Style Identity doesn't return a value. Return'ing is simulated by passing what comes after the function (the continuation) as a function object. In many functional languages continuations are so central to how things work that this is how you return values (and those languages are optimized for doing this). For those of you like me who grew up with the imperative children of pascal, this may be somewhat mind-bending at first. It will also likely have you saying "why would anyone do this?"

Rather than steal his entire article, go see Wes Dyer's article on the subject (where I got the identity example) for more about why one might do this outside of a language (like Scheme or Erlang) where this idiom is apparently the norm.

For even more details (including why this isn't quite CPS) see this by Don Box.

BTW, my answer to "Why do this?" is: "When it is the best way to solve the problem at hand." That I don't know when that will be yet, doesn't really concern me. I don't always learn things with a specific application in mind. Sometimes, I learn things so that when a problem arises, I have a lot of different tools in my toolbox. In other words, I am learning it because its interesting, a bunch of people smarter and more knowledgeable than me have found uses for it, and I might someday too (and I definitely won't if I don't know about it!)

Perhaps the best reason to learn this stuff is because Microsoft has put some sharp tools in the C# toolbox and I think its better to know how they work so that - even if I rarely ever take them out - I don't get cut on them while rummaging around in there.

UPDATE: For Wes's take on why it's important, see here (and really his whole series on the topic is worth the read!)

UPDATE2: If you want to take a deeper tour of these and many other functional concepts, this series of articles by Dustin Campbell goes far and wide if you follow all the links (and the links' links and so on...)

There were some exciting announcements from Apple at WWDCtoday! Being a Mac OS X user (though still chugging along with a mid-2007 Whitebook with cracks on the edges and a not-bright-enough screen) and having an iPhone (with dust creeping under the screen), I'm pretty excited about all the new announcements. Here are my initial reactions:

  • New Laptops
    • I really like the idea of built-in batteries. Being a student in college, I'm around power outlets most of the time, but even in class, having this increased power efficiency really helps. I'm not too worried about having to buy extra batteries because I won't ever be that far away from an outlet. If Apple is going to charge me for $129 for a new battery anyway, I don't mind getting a longer-lasting (both one-charge-wise and life-time-wise). Though, I have heard good things about Fastmac batteries, which are only $99.
    • The old unibody macbook branded as a MacBook Pro now just makes sense. The lower prices and the (re)addition of a firewire port help to sweeten the deal for potential switchers to the OS X platform.
    • I at first was extremely excited about the price drop of the lowest end MacBook Pro to $1700, but I'm not stoked about the fact that it doesn't have discrete graphics. Though I don't do much gaming, having discrete graphics (after going through this horrible experience with integrated graphics only on my Macbook) is important to me. Guess I'd have to go one step up...
  • New iPhone
    • The upgraded camera seems like it would be the one killer feature for me. Having focus opens up many creative possibilities (without resorting to cases and such to provide macro capability).
    • Find My iPhone, in which you can track down a missing iPhone through MobileMe, sounds incredibly awesome (whenever I can fork out the money for MobileMe...)
    • The addition of hardware peripherals to the iPhone platform adds amazing possibilities. Turn-by-Turn GPS at last!
  • Snow Leopard
    • The updates to the Finder seem pretty cool. The Quicklook tweaks look pretty useful (though I admit I don't use Quicklook much as it is now). I actually don't hate the Finder as much as a lot of other people do. The one thing I'm looking for is a way to have a 2-pane view in which I could easily copy and paste things (such as dragging to Applications from a disk image)
    • OpenCL, which as I understand it is offloading normally CPU-bound tasks to the graphics processor, sounds like it could be amazing (all the more reason to get a computer with discrete graphics)
    • Text-Expander-like capabilities (predictive text-filling in based on snippets) integrated into the system seems like it could be be very useful.

All-in-all, a pretty eventful WWDC. Going to Google I/O a week ago and experiencing the conference thing (and getting a free Google Ion phone in the process), I would love to go to WWDC next year and see what (Steve Jobs, hopefully) has in store for us.



Labor unions have been around for decades.  They formed as a way to prevent management from treating labor unfairly and to guarantee certain rights for their members.  Labor unions subsequently rose in power and began to handicap companies ability to cut costs and maximize shareholder value.  In this way, they are counter capitalism, since capitalism is meant to maximize profits for it's shareholders.  Now, this isn't to say that labor unions are evil or a bad idea, just that the two ideas have fundamentally opposite goals.

Unfortunately, where labor unions once were the champions of honest hard working people, they became the poster child for corruption and greed.  It's no coincidence that the labor unions rose in power at the same time the Italian mafia rose in power.  Now, the nefarious element has been largely removed from the unions, but the greed still exists.  Ultimately, union leaders and members could not see the correlation between their increasingly skyrocketing salary, retirement and health demands and managements increased use of outsourcing.  After all, nothing about capitalism requires the use of domestic labor.  This has contributed to the down fall of not only companies, but entire industries and sections of the country.  Nowhere is this more evident than Detroit and the auto industry.  It's a shame that management and labor couldn't see the end coming and agree to make individual sacrifices for the good of everyone.  This doesn't mean that the American auto industry would have been saved, but it would have made it easier to compete if people weren't making $35+ an hour for assembly line jobs.  My father ran a manufacturing company for almost 20 years and in the end he was a victim of the same fate.  People sweeping the floor at his company were earning $20/hr.  In the end he just couldn't compete with foreign labor prices.

Chicago is going through its own labor union negotiations right now.  In an effort to save 1,500 city jobs, union leaders are meeting with the mayor and his administration to come to some sort of agreement.  This includes concessions on both sides, which is welcome news.  It seems as though people are starting to understand that the economy is constantly changing and shifting.  That is until I read this quote from the union chief:

"There's got to be assurances that, 10 years from now, these jobs that our members have are still gonna be there for them," he said.

It's amazing to think that people are still looking for 10+ year job security in such a changing environment. If you have a guaranteed job for 10 years, what incentive is there for you to change?  Instead of figuring out how we can take what we have and freeze it in time to preserve it, we should be figuring out how we can better equipment the people whose jobs are going to be obsolete to tackle new jobs.  One of the strange facts about the current economy is that there are thousands of jobs that are still vacant and with no supply of people filling the positions.  Unfortunately, these jobs  are in emerging and sometimes complex industries like IT and health care.   We should be retraining people in these industries rather than trying to maintain and blue collar / assembly line economy.



I have a very simple test application up on Google App Engine. See gregrluckapphelloworld.appspot.com.

80MB heap limit

Go to gregrluckapphelloworld.appspot.com. Each time you hit is exactly 10MB gets added to Ehcache in-process cache. This is an intentiontal memory leak designed to find out how much you stick in the heap.

The answer is around 80MB. I suspect, taking Jetty into account that there is an -Xmx100m setting in play.

Crashed sites do not recover immediately or start a new instance.

When you get an OutOfMemory error the site is cooked. There should be some monitoring that notices and takes it down. That is not the case.

I have a wget script which, every 30 seconds, does
while true; do wget "http://gregrluckapphelloworld.appspot.com/"; sleep 30;  done;
The answer is that the dead site stays down for 5 minutes (10 repetitions of my script). And no new instance gets fired up. Your whole site is down.

Static content is not distributed through the Google CDN

On the page I put an image. I did not configure it as static. I downloaded it and got the IP 74.125.19.141 which is in Mountain View, California. I then marked the images as static in appengine-web-app and redeployed. There was no effect on the serving location or speed of download. It may be that the files are served from the static content location You would expect this to be distributed via Google's CDN. Here is the header you get from the static content servers.
HTTP/1.0 200 OK
  Date: Tue, 16 Jun 2009 09:47:01 GMT
  Expires: Tue, 16 Jun 2009 09:57:01 GMT
  Cache-Control: public, max-age=600
  Content-Type: image/jpeg
  Server: Google Frontend
  Content-Length: 237952
  Connection: Keep-Alive
Another interesting thing - cache expiry is set to 10 minutes. A CDN will normally set the TTL longer and rely on a technique such as resource renaming to overcome browser cache issues.

Conclusion

None of this is good. The first is a very serious limitation. The last two are killers for running a production app. Hopefully Google will fix these things.

Pascal Van Cauwenberghe has written a great post on estimating business value, tying it into a feature-injection style template. I particularly like the idea of calculating business velocity, and showing value earned over cost on a visible chart.

Even though we know that cost accounting isn’t useful without looking at ROI, many companies still have this focus (how many people have had problems getting hold of sharpies because they’re "too expensive"? Coloured post-its? Free coffee?)

Perhaps by making the return on investment over time apparent to everyone, we can motivate the team, show the value we’re earning and gain the trust of the business at the same time.

As an aside, I remember one client where the deadline was very tight, but nobody wanted to work overtime or weekends. Our PM asked us if there was anything we’d like to have which would help us work more effectively. We asked for - and got - fresh fruit every day. The difference in our work - both the amount and quality - was noticeable! (We already felt very well respected, so I discount the placebo effect here).

It’s amazing how much difference a few pounds of expense can make.

Disclaimer: ThoughtWorks embraces the individuality of the people in the organization and hence the opinions expressed in the blogs may contradict each other and also may not represent the opinions of ThoughtWorks.