<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-10538439</id><updated>2012-02-10T00:57:51.520-08:00</updated><category term='software communication scrum'/><category term='agile architecture'/><category term='testing'/><category term='moxy'/><category term='self organization'/><category term='collaboration'/><title type='text'>Kevin Klinemeier's Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>30</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-10538439.post-349345412852625344</id><published>2011-02-14T11:26:00.000-08:00</published><updated>2011-02-14T11:26:38.869-08:00</updated><title type='text'>My blog is moving locations</title><content type='html'>My blog has changed locations! &amp;nbsp;The folks at Pugetworks have been great to work with and I enjoy being part of a group of writers. &amp;nbsp;I've moved over some of the best content, and written some new articles, collect them all at:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://pugetworks.com/author/kevin/"&gt;http://pugetworks.com/author/kevin/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;-Kevin&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-349345412852625344?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/349345412852625344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=349345412852625344' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/349345412852625344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/349345412852625344'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2011/02/my-blog-is-moving-locations.html' title='My blog is moving locations'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-8698756424553596235</id><published>2010-02-02T11:44:00.001-08:00</published><updated>2010-02-02T11:51:41.029-08:00</updated><title type='text'>Relative estimates are like a stagecoach</title><content type='html'>If you're having trouble getting across the idea of relative estimates (story points) vs velocity to your management, try this approach:&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Estimate stories using a distance measure.  Furlongs for fun, miles if you're a boring American, kilometers if you're a boring person on the rest of the planet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Your team velocity is measured in furlongs-per-sprint.  This makes clear the separation between how much work needs to be done and how fast a team can complete it.  It calls out the knobs that management can turn immediately: go faster, do less work.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For the vehicle, consider a stagecoach.  Every new horse added to a stagecoach adds to its potential speed.  Four horses is better and faster than one horse, but not four times better.  There's a point where you're better off with two stagecoaches.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Breakdowns:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Another popular analogy is rocks-in-a-box.  Your velocity is called capacity, and described as a box for the Product Owner to fill with rocks.  Rock size is estimated by the team.  Lots of small rocks do a better job of filling up the box.  This point, that small well-understood stories are easier to complete, is missing from the stagecoach analogy.  (If the miles are short, they go by faster?  Doesn't quite work.)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-8698756424553596235?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/8698756424553596235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=8698756424553596235' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/8698756424553596235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/8698756424553596235'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2010/02/relative-estimates-are-like-stagecoach.html' title='Relative estimates are like a stagecoach'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-8857938017089163150</id><published>2009-11-09T16:36:00.001-08:00</published><updated>2009-11-09T18:14:49.047-08:00</updated><title type='text'>Questions to ask when you want something</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Can I have it now?  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;No.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;Can you tell when I can have it?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;No.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;When can you tell me when I can have it?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I don't know.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Do you need something from me?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;No.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Bullshit.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Maybe this should be a flowchart.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-8857938017089163150?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/8857938017089163150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=8857938017089163150' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/8857938017089163150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/8857938017089163150'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2009/11/questions-to-ask-when-you-want.html' title='Questions to ask when you want something'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-2866492639776873340</id><published>2009-08-26T12:31:00.000-07:00</published><updated>2009-08-26T13:06:28.946-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='moxy'/><title type='text'>Testing with Moxy</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Overview&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Build&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;proxies that pass through most requests, but create mock results on well-known data.&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;Our situation&lt;/span&gt;&lt;br /&gt;We needed to be able to verify the behavior for error conditions from our Selenium (web) tests.  We had already created mock services that would return these results.  We then had to manage when we connected to which endpoint, which put the expectation about behavior outside the test and in the server configuration.  In order to do a single regression pass, we had to stop and reconfigure the server. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Our solution&lt;br /&gt;&lt;/span&gt;We created Moxies (mock proxies), which most of the time are just a plain passthrough to the real endpoint from our vendors' test systems.  For a well known set of data (addresses in Broken Arrow, Oklahoma) the Moxy returns error conditions.  Those addresses and their expectations are defined in a single class, shared both by the Moxy implementation and the tests. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Benefits&lt;br /&gt;&lt;/span&gt;Test real success and mock failure in same server configuration.&lt;br /&gt;Data and its expectation is in sync (shared classes).&lt;br /&gt;Code is explicit about which tests depend on which Moxies, and which specific behaviors.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Future&lt;/span&gt;&lt;br /&gt;With the same solution we expect to create a set of test cases that do not rely on the availability of the vendor test systems, based on similar conventions.  (Eureka, CA)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Other implementations&lt;/span&gt;&lt;br /&gt;We considered using wrapper objects injected via Spring to accomplish the same thing with less monkeying around with endpoints.  This would avoid needing to deploy a real http mock service, and avoid issues around certificate verification and authentication.  However, an injected solution would require deploying the mock software on all the client machines, and tweaking its configuration so that the wrapper bean is injected in our test environment, but not production.  The injection solution also doesn't test the parsing of the error response, though that should probably be done in unit tests anyway.&lt;br /&gt;&lt;br /&gt;If we were using a ESB like Mule, we could have configured Mule to redirect the requests based on the data, and used our mock services unchanged, and the test system configuration also unchanged. &lt;br /&gt;&lt;br /&gt;Some solutions avoid having to use key data in the request object by manipulating http header info instead.  This wasn't an option for us, unless we create some kind of signal for that header all the way through to our public pages.  That seemed too invasive for our situation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Closing&lt;/span&gt;&lt;br /&gt;It works for us, and has a cool name*.  What more could you want?&lt;br /&gt;&lt;br /&gt;* Yes, you could probably more accurately describe this as a decorator.  But Mockorator isn't nearly so awesome a name.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-2866492639776873340?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/2866492639776873340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=2866492639776873340' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/2866492639776873340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/2866492639776873340'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2009/08/testing-with-moxy.html' title='Testing with Moxy'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-717566001509414800</id><published>2009-08-03T23:58:00.000-07:00</published><updated>2009-08-03T23:55:43.197-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='collaboration'/><category scheme='http://www.blogger.com/atom/ns#' term='self organization'/><category scheme='http://www.blogger.com/atom/ns#' term='agile architecture'/><title type='text'>Leading Self Organized Teams</title><content type='html'>&lt;h2 id="head-061999430e5d9279237e82972a17ef8be0203ceb"&gt;Self Organization, Collaboration != Fire Your Leadership&lt;br /&gt;&lt;/h2&gt;One of the questions I've tackled with the agile teams I've worked with is how to find a balance between the need for direction and quick decisions with the open and self-organizing approaches that are recommended for teams practicing agile processes.  A lot of this perceived conflict comes from people overstating the basics.  In particular:&lt;br /&gt;Self Organization != No Leadership.  Collaborative Approach != Everyone Votes On Everything.&lt;br /&gt;&lt;h2 id="head-061999430e5d9279237e82972a17ef8be0203ceb"&gt;Core Values:&lt;/h2&gt; &lt;span class="anchor" id="line-2"&gt;&lt;/span&gt;&lt;p class="line867"&gt;&lt;em&gt;Self Organization:&lt;/em&gt; Invite owners and participants rather than assigning people to teams &lt;/p&gt;&lt;p class="line867"&gt;&lt;em&gt;Transparency:&lt;/em&gt; Discuss topics openly, rather than among a separate team. &lt;span class="anchor" id="line-5"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-6"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="line867"&gt;&lt;em&gt;&lt;strong style="font-weight: normal;" class="highlight"&gt;Collaboration&lt;/strong&gt;:&lt;/em&gt; The point of the self-organized group &lt;span class="anchor" id="line-7"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-8"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="line867"&gt;&lt;em&gt;Direction:&lt;/em&gt;  The owner is responsible for driving to dates, providing major guidance (sometimes from above), and deadlock resolution.&lt;/p&gt;&lt;p class="line867"&gt;&lt;em&gt;Review:  &lt;/em&gt;Periodic review of practices and applications is key to success.&lt;/p&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h2 id="head-c25c6c1fc0564608a26eae5075153676c2ccbcea"&gt;Example: Spacely Sprockets Quality Issue&lt;/h2&gt; &lt;span class="anchor" id="line-13"&gt;&lt;/span&gt;&lt;p class="line862"&gt;Problem: All the sprockets we've got are throwing &lt;span class="nonexistent"&gt;NullPointerExceptions&lt;/span&gt;. &lt;/p&gt;&lt;p class="line874"&gt;The Development Director in this case wants to delegate this task to the team.  In order to do that, she asks for volunteers to be the "owner" for this issue, and Olaf steps up.  After consulting with the Development Director for parameters (due dates, budget, etc) the first thing Olaf does is send an invitation: (Self Organization) &lt;/p&gt;&lt;ul&gt;&lt;li style="list-style-type: none;"&gt;To: yourWholeTeam &lt;span class="anchor" id="line-18"&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: none;"&gt;Subject: Spacely Sprockets Quality Issue &lt;span class="anchor" id="line-19"&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: none;"&gt;Hello Team, &lt;span class="anchor" id="line-20"&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: none;"&gt;We need to determine whether to stay with Spacely Sprockets, change to Cogswell Cogs, or pursue some third option. if you're interested in participating, send me an email and I'll include you in tomorrow's meeting. &lt;span class="anchor" id="line-21"&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: none;"&gt;-Olaf &lt;span class="anchor" id="line-22"&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="line874"&gt;The group meets a couple of times (&lt;strong style="font-weight: normal;" class="highlight"&gt;Collaboration&lt;/strong&gt;), trades emails (via whole team mailing list, for Transparency) and works towards a recommendation. One participant suggests Gary's Gears, but Olaf shares that Gary's Gears are outside the budget for the project. (Direction). Absent of that option, the group finds consensus on staying with Spacely after an impassioned speech by George J., one of their salesmen. Olaf shares that recommendation with the rest of the team, then the Development Director, who puts the recommendation into place after a few additional questions/clarifications (more Direction). &lt;/p&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h2 id="head-a33ba0c68b060de23e2f70458cabee348e236e6c"&gt;Common Problems&lt;br /&gt;&lt;/h2&gt; &lt;span class="anchor" id="line-25"&gt;&lt;/span&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h3 id="head-34d15957b471795e59f4cffbd2feb445b26d8abb"&gt;Self Organization Problem: nobody signs on&lt;br /&gt;&lt;/h3&gt; &lt;span class="anchor" id="line-26"&gt;&lt;/span&gt;&lt;p class="line874"&gt;Often you'll be expecting "the usual suspects" to show up when you invite people to collaborate. Sometimes you'll be surprised to find no responses to your hot topic. As the owner, this gives you the opportunity to find out why. This may be for many reasons: &lt;span class="anchor" id="line-27"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-28"&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;People are busier than expected &lt;span class="anchor" id="line-29"&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;People are tired of working with the issue &lt;span class="anchor" id="line-30"&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;People feel that the solution is obvious &lt;span class="anchor" id="line-31"&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;People feel that the recommendation won't result in change. &lt;span class="anchor" id="line-32"&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h3 id="head-7b9cf20971c94d6256fb1a3c70de8a9d5cd6488e"&gt;What to do:&lt;/h3&gt; &lt;span class="anchor" id="line-33"&gt;&lt;/span&gt;&lt;p class="line874"&gt;Talk to your usual suspects with these possibilities in mind. The major advantage of the process in this case is that as the owner you are aware of these problems at the beginning rather than the end of the process. &lt;span class="anchor" id="line-34"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-35"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h3 id="head-f613e007c067086f770a8f93b327b8a8b3f71f7e"&gt;Self Organization Problem: everybody signs on&lt;/h3&gt; &lt;span class="anchor" id="line-36"&gt;&lt;/span&gt;&lt;p class="line874"&gt;Instead of "the usual suspects", you get the whole department.  Reasons for this include: &lt;span class="anchor" id="line-37"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-38"&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Concern that some aspects of the issue are being ignored or are unknown to the group &lt;span class="anchor" id="line-39"&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Concern about "the expected outcome" &lt;span class="anchor" id="line-40"&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Size/Impact of recommendation &lt;span class="anchor" id="line-41"&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h3 id="head-7b9cf20971c94d6256fb1a3c70de8a9d5cd6488e-2"&gt;What to do:&lt;/h3&gt; &lt;span class="anchor" id="line-42"&gt;&lt;/span&gt;&lt;p class="line874"&gt;Hold a first meeting and have a round-table where you invite each participant to share what motivated them to participate. &lt;span class="anchor" id="line-43"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-44"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="line874"&gt;People who feel that they're alone in a concern have an opportunity to share it, and can hear others if they exist. Those who are worried about an "expected outcome" can share their point of view. If the source is that the impact of the recommendation is huge, then team members have an opportunity to voice general concerns and witness for themselves the process by which the recommendation is being made.  Sometimes just having the preliminary session is enough -- the team can identify when enough of each viewpoint exists and will drop out satisfied that their viewpoint is represented.&lt;/p&gt;&lt;p class="line874"&gt;Another approach is to assure the team as a whole that there will be an opportunity to review the recommendation before it is "ratified."  This can make team members feel less urgency about allowing others to tackle a difficult or contentious issue.&lt;br /&gt;&lt;/p&gt;&lt;p class="line874"&gt;You may be tempted as the Owner to be aggressive in this case about reducing team size. Be sure that you are keeping in mind that the real goal is not to simply make a recommendation, but to have it understood and implemented by the entire team.  To this end, it may be more effective to allow for some up-front "inefficiency" in order to get everyone on the same page and reach the real desired outcome faster as a result.&lt;br /&gt;&lt;/p&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h3 id="head-924fdfe5b179f01cca0c31a4ae4c4c4be5f774df"&gt;Direction Problem: small project&lt;/h3&gt; &lt;span class="anchor" id="line-49"&gt;&lt;/span&gt;&lt;p class="line874"&gt;Sometimes this all seems like a lot of effort, with more time spent sending invitations and setting up meetings than it would take to do the work. &lt;/p&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h3 id="head-7b9cf20971c94d6256fb1a3c70de8a9d5cd6488e-3"&gt;What to do:&lt;/h3&gt; &lt;span class="anchor" id="line-52"&gt;&lt;/span&gt;&lt;p class="line874"&gt;Use IM and/or email for self-organization. Set a deadline for response (self-organization), and list your planned actions by that deadline (Direction, Transparency). Ex: &lt;/p&gt;&lt;ul&gt;&lt;li style="list-style-type: none;"&gt;To: yourWholeTeam&lt;/li&gt;&lt;li style="list-style-type: none;"&gt;Subject: I hate the PMD "use if x==y not if x!=y" rule &lt;/li&gt;&lt;li style="list-style-type: none;"&gt;&lt;span class="anchor" id="line-56"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: none;"&gt;Hey all, Can someone tell me why I shouldn't hate this rule?  If nobody objects, I'll remove it on Wednesday. &lt;/li&gt;&lt;li style="list-style-type: none;"&gt;&lt;span class="anchor" id="line-57"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: none;"&gt;-Developer Danielle &lt;span class="anchor" id="line-58"&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h3 id="head-0c5e9d6160edbec5ca3b7752e49c7dc0ecdcb8c1"&gt;Collaboration Problem: can't reach consensus&lt;/h3&gt; &lt;span class="anchor" id="line-59"&gt;&lt;/span&gt;&lt;p class="line874"&gt;Rational people can disagree on a subject.  Time doesn't always allow all avenues to be examined. &lt;span class="anchor" id="line-60"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-61"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h3 id="head-7b9cf20971c94d6256fb1a3c70de8a9d5cd6488e-4"&gt;What to do:&lt;/h3&gt; &lt;span class="anchor" id="line-62"&gt;&lt;/span&gt;&lt;p class="line874"&gt;This is the "big job" of the owner. It's the owner's responsibility not only to identify when it's time to just make the call, but to also make all the participants feel that they've been heard even if they haven't been agreed with. &lt;/p&gt;&lt;p class="line874"&gt;Every time the process is used without the need for this outcome are like money in the bank.  That money (trust, really) is expended in these situations.  If you've got a positive balance, then this is just a a problem.  If you're overdrawn, then this situation can become a fiasco. Team members must feel that the situations where the owner makes the call without consensus are rare, and due to issues that are a toss-up, or due to outside pressure. If you're doing a lot of this, it's probably an issue that should be considered in the process review. &lt;/p&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h3 id="head-427bd357f468f8caf43c5c32c0f69b26d324dcec"&gt;Transparency Problem: When should I include everybody?&lt;/h3&gt; &lt;span class="anchor" id="line-67"&gt;&lt;/span&gt;&lt;p class="line874"&gt;Is copying yourWholeTeam on *everything* really the recommendation?  What if they're unlikely to care and it's just noise? &lt;/p&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h3 id="head-7b9cf20971c94d6256fb1a3c70de8a9d5cd6488e-5"&gt;What to do:&lt;/h3&gt; &lt;span class="anchor" id="line-70"&gt;&lt;/span&gt;&lt;p class="line874"&gt;Use a restating of the golden rule to determine what to send to the whole group: If you weren't an active participant, would you want to know about this part of the discussion? Err on the side of Transparency. &lt;span class="anchor" id="line-71"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-72"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="line867"&gt; &lt;/p&gt;&lt;h2 id="head-a12b3859f3ca717e4f753b7ac7bb09144da0b9a7"&gt;Criteria For Review&lt;/h2&gt; &lt;span class="anchor" id="line-79"&gt;&lt;/span&gt;&lt;p class="line874"&gt;These criteria help determine success of this approach and your specific practices: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Does everyone feel they understand the approach?&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Does everyone feel that quality recommendations are being made? &lt;/li&gt;&lt;li&gt;Do team members feel involved, not dictated to? &lt;/li&gt;&lt;li&gt;Are recommendations timely and within expected parameters, ie conforming to Leadership's direction?&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;Last Words&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To restate a problem from above, it's important to keep in mind that the end goal isn't a decision, its a decision whose spirit is implemented and upheld team wide.  I use this approach not because it makes everyone feel good, but because it's the most effective way to get real results.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-717566001509414800?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/717566001509414800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=717566001509414800' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/717566001509414800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/717566001509414800'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2008/12/leading-self-organized-teams.html' title='Leading Self Organized Teams'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-5467771942950769637</id><published>2009-04-15T00:52:00.001-07:00</published><updated>2009-04-15T01:01:52.710-07:00</updated><title type='text'>Rails Hates me</title><content type='html'>So, I've got a little extra time, and I figured it was time to get back to my rails project.  I've half written this character-timeline-thingy maybe three or four times but never quite completed it.  As I recall, I had it almost-completely-working maybe a year and a half ago, so I thought I'd take it out for a spin on my new macbook with its built-in rails mojo.&lt;br /&gt;&lt;br /&gt;I grabbed my old files off of my external hard drive and:  No love.  No mysql.  Oh, of course.  Installed mysql and a visual editor, felt warm and fuzzy about that process.  Created the tables with the table-creation script I created when I used this last time, made another mental note to look into rails' migrations and&lt;br /&gt;&lt;br /&gt;$ &lt;span style="font-style: italic;"&gt;rake&lt;/span&gt;...&lt;br /&gt;&lt;br /&gt;Fail.  My tests are talking about fixtures that have some kind of problem.  This is fixed, and something else doesn't work, a nil where I didn't expect it.  Oookay, bwuh?  Maybe this is just old and I'll start over.  It's got deprecation warnings in it too, so meh.&lt;br /&gt;&lt;br /&gt;$ mv timemachine timemachineOldAndBusted&lt;br /&gt;$ rails timemachine&lt;br /&gt;$ rake&lt;br /&gt;&lt;br /&gt;Fail again.  The mysql gem isn't installed by default anymore.  Okay, so:&lt;br /&gt;&lt;br /&gt;$ sudo gem install mysql&lt;br /&gt;&lt;br /&gt;Fail again.  some crap about headers and native extensions.  I turn to google, and go through a lot of gymnastics around installing stuff from source, upgrading gems itself, etc. etc.  I follow all the directions I see in a pretty helpful article, everything seems to be passing and:&lt;br /&gt;&lt;br /&gt;$ mv timemachine timemachineFail&lt;br /&gt;$ rails -d mysql timemachine&lt;br /&gt;$ rake&lt;br /&gt;&lt;br /&gt;Fail.  Now it says that the mysql gem isn't installed, but gem list says it is.  Back to google, now the suggestion is to do some trickery with 64-bit mysql vs 32-bit mysql and binary hacking the broken mysql.bundle file to fix the problem.&lt;br /&gt;&lt;br /&gt;This all feels like why Java and platform independence is still important.  I'm tired of mucking with building from source into my operating system.  AppEngine supports Java, right?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-5467771942950769637?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/5467771942950769637/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=5467771942950769637' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/5467771942950769637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/5467771942950769637'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2009/04/rails-hates-me.html' title='Rails Hates me'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-6060904261466096543</id><published>2009-03-25T13:27:00.000-07:00</published><updated>2009-03-25T13:36:12.166-07:00</updated><title type='text'>Easy self-improvement</title><content type='html'>What's the easiest thing you can do to improve yourself?  Take a compliment, and make it twice as true.&lt;br /&gt;&lt;br /&gt;What's your favorite compliment of all time, or of the last year?  Chances are, your complimentor has identified something that comes easily to you, a natural gift of yours that was appreciated.  It may be more valuable to improve something that you're already pretty good at than try to rebuild yourself in something that is difficult.&lt;br /&gt;&lt;br /&gt;Let's say it's some mode of communication, maybe written communication.  Where else can you use this skill?  How could you be even better at it?  What is it that makes you good, exactly? &lt;br /&gt;&lt;br /&gt;These kinds of questions, when asked about something you're already doing well have a much lower "effort."  If you've picked an area you're good at, that you're excited about, you may find that they return energy to your day instead of subtract it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-6060904261466096543?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/6060904261466096543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=6060904261466096543' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/6060904261466096543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/6060904261466096543'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2009/03/easy-self-improvement.html' title='Easy self-improvement'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-7274412461794415073</id><published>2009-02-09T10:12:00.000-08:00</published><updated>2009-02-09T10:44:18.336-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software communication scrum'/><title type='text'>Cut n Paste to lower communication barriers</title><content type='html'>At work, we have a weekly newsletter.  I used to read it, but I don't anymore.  It used to just be in email, and I'd skim some of it as it came by before I deleted it. &lt;br /&gt;&lt;br /&gt;Now, it's a document attached to an email.  It requires just one more click to see it, and I don't do it.  It had some nice information in it -- new hires, birthdays, other company news.  Stuff I could read "incidentally".  Clicking that link feels like committing to reading the whole document, rather than just skimming over what's already in my box.&lt;br /&gt;&lt;br /&gt;I've been thinking about how I can lower barriers when I communicate as well.  The easy one is that instead of just mailing a link (which most people won't click on), I paste the whole document into my email. &lt;br /&gt;&lt;br /&gt;The same thinking has led to a lot of physical printouts in our office.  This strikes some people as funny -- we're a tech company, yet much of our process is documented on giant sticky notes.  Yet the results are clear: a giant sticky note next to the fridge communicates much more effectively than email, or a diagram in a folder in Sharepoint.&lt;br /&gt;&lt;br /&gt;But what other barriers exist in our group that I'm not aware of?  We've worked pretty hard to reduce them: we move desks when we reorganize teams so members can sit together, we aggressively encourage pair programming, our scrum process has its standups, etc. &lt;br /&gt;&lt;br /&gt;A better question might be: how do we identify them?  I'm not aware of a metric that I can rely on.  Things come up in the retrospective, but that's just once every three weeks.  Perhaps the real story here is about using all channels of communication.&lt;br /&gt;&lt;br /&gt;In my email example, I have only one channel so I need to make sure it's as effective as possible.  Even then, I don't really expect everyone to get the information I'm sharing.&lt;br /&gt;&lt;br /&gt;When I give presentations, I try to say my point three times, and in three different ways: Once in text, once with a picture, and once verbally.  Maybe there's a correlation there when I'm looking to drive change in our office (or just hold us to changes we've already agreed on):  A poster, an email, and a verbal reminder during standup.&lt;br /&gt;&lt;br /&gt;I'm going to look for things where I'm using only one mode of communication, and either reduce my expectations around that message or increase my modes.  (make a poster, send an email, include it in our standups)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-7274412461794415073?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/7274412461794415073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=7274412461794415073' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/7274412461794415073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/7274412461794415073'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2009/02/cut-n-paste-to-lower-communication.html' title='Cut n Paste to lower communication barriers'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-7216050363172786029</id><published>2008-09-16T17:45:00.000-07:00</published><updated>2008-09-16T18:08:13.019-07:00</updated><title type='text'>Scrum Baseball</title><content type='html'>When talking about Scrum, the question often comes up about "customization."  Each team is expected to customize things to their environment.  But when you're adopting it for the first time, how far is too far?  I've heard other analogies surrounding baseball, here's mine:&lt;br /&gt;&lt;br /&gt;What is baseball?  Softball is still pretty much baseball.  T-ball is still pretty much baseball.  What about Cricket?  While it has bats and balls and running around, it isn't baseball.&lt;br /&gt;&lt;br /&gt;My "short list" for scrum is:&lt;br /&gt;&lt;br /&gt;Work is stack ranked in a product backlog, sized relatively&lt;br /&gt;Work may begin before product backlog is "complete"&lt;br /&gt;Work done in iterations&lt;br /&gt;Daily standups for status&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-7216050363172786029?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/7216050363172786029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=7216050363172786029' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/7216050363172786029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/7216050363172786029'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2008/09/scrum-baseball.html' title='Scrum Baseball'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-221112333441798269</id><published>2008-01-08T14:28:00.000-08:00</published><updated>2008-01-08T14:34:11.336-08:00</updated><title type='text'>Code Coverage for Eclipse redeux: EclEmma</title><content type='html'>In a previous entry, I lamented that I couldn't get instant feedback for the coverage results of my unit tests in eclipse.  A coworker (David Koontz of SolutionsIQ) pointed me at &lt;a href="http://www.eclemma.org/"&gt;EclEmma&lt;/a&gt;.  In a nutshell, it works.&lt;br /&gt;&lt;br /&gt;It gives me line-by-line coverage, highlighted in green, yellow, and red like the coverage reports I get from Cobertura.  In addition to file-by-file coverage, EclEmma also summarizes coverage reports for an entire project in an Eclipse view much like the Cobertura's roll-up behavior.&lt;br /&gt;&lt;br /&gt;It plugs into Eclipse smoothly via update site, and works with all my tests including configuration details with Spring, Hibernate, HSQL, etc.  Usage was simple: if I had a JUnit execution defined in Eclipse (generated automatically via runAs .. unit test), then I can reuse it with EclEmma.  Run As ... Coverage Test is also available.&lt;br /&gt;&lt;br /&gt;My only complaint is some strange behavior around code that throws exceptions.  If a block of code throws an exception partway through, EclEmma counts that entire block as untested.  The authors point to this being a limitation of the Emma code coverage tool.  My code doesn't generally throw a lot of expected exceptions, so it hasn't been a major issue.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In general, happy as a clam am I!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-221112333441798269?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/221112333441798269/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=221112333441798269' title='27 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/221112333441798269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/221112333441798269'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2008/01/code-coverage-for-eclipse-redeux.html' title='Code Coverage for Eclipse redeux: EclEmma'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>27</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-3315917756611054168</id><published>2007-08-29T09:23:00.001-07:00</published><updated>2007-08-29T09:36:16.573-07:00</updated><title type='text'>Integration Testing more important than Unit Testing</title><content type='html'>When I'm learning a new framework, strict unit testing isn't very helpful.  To illustrate, here's an example:&lt;br /&gt;&lt;br /&gt;I want to write a command object of some sort that interacts with &lt;a href="http://www.jboss.org/products/jbpm"&gt;jbpm&lt;/a&gt;.   Jbpm is a workflow engine, with nodes and transitions.  I need to look up a process (a collection of nodes and transitions), select a node and tell it to take a particular transition.&lt;br /&gt;&lt;br /&gt;If I use EasyMock to ensure that I'm testing only my code, I can test whether the code is doing what I expect.  However, that doesn't answer the most important question:  Am I doing this the right way?&lt;br /&gt;&lt;br /&gt;In my example, there are a couple of ways to look up nodes, and a couple of situations where the framework behaves differently than I expect.  I can't find any of that until I do integration testing.&lt;br /&gt;&lt;br /&gt;The paradox is that the authors of the framework don't have questions about which approach in their own framework is the correct one.  Hence, testing integrations with the framework isn't attempted, and anything not attempted isn't factored into the design.&lt;br /&gt;&lt;br /&gt;Bottom Line:  Easy integration testing is key for rapid framework adoption.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-3315917756611054168?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/3315917756611054168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=3315917756611054168' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/3315917756611054168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/3315917756611054168'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2007/08/integration-testing-more-important-than.html' title='Integration Testing more important than Unit Testing'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-6952570778114209993</id><published>2007-05-30T11:40:00.000-07:00</published><updated>2007-05-30T11:42:39.799-07:00</updated><title type='text'>Eclipse instant code coverage?</title><content type='html'>In general, I've drunk all the test-first kool-aid there is.  My development is a constant cycle of write test, run test, write code, run test.  Repeat until I think I'm done.&lt;br /&gt;&lt;br /&gt;I really like code coverage tools, as they let you know if you're as done as you think you are.  Are you testing that else clause or that exception case?  Good stuff.&lt;br /&gt;&lt;br /&gt;So why can't Eclipse show me which lines were covered by my *last* test run?  I think that would be pretty useful, and it seems like the pieces are there to make it happen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-6952570778114209993?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/6952570778114209993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=6952570778114209993' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/6952570778114209993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/6952570778114209993'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2007/05/eclipse-instant-code-coverage.html' title='Eclipse instant code coverage?'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-7193094218935990047</id><published>2007-05-22T10:54:00.001-07:00</published><updated>2007-05-22T11:05:44.212-07:00</updated><title type='text'>The Deal with Documents</title><content type='html'>When working up some process documentation, our group had a little bit of a revelation:&lt;br /&gt;&lt;br /&gt;Documents exist to make a decision.&lt;br /&gt;&lt;br /&gt;This single statement really helped us streamline what we were doing with our documentation, and our process itself.  At each stage, we asked "What decision is trying to be made?  What information is needed for that decision?"  Everything else was junk, and we cut it out of the document.&lt;br /&gt;&lt;br /&gt;Every time I write a document now, I ask myself that question.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-7193094218935990047?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/7193094218935990047/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=7193094218935990047' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/7193094218935990047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/7193094218935990047'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2007/05/deal-with-documents.html' title='The Deal with Documents'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-2371444893277919596</id><published>2007-04-24T13:46:00.000-07:00</published><updated>2007-04-24T14:02:22.293-07:00</updated><title type='text'>LinkedIn end-run.</title><content type='html'>I was contacted today, by phone, by  Dan Payne from &lt;a href="http://opsware.com"&gt;Opsware&lt;/a&gt;. He "found" my information via &lt;a href="http://linkedin.com"&gt;LinkedIn&lt;/a&gt;.  This was surprising to me, since  I don't know Dan and was under the impression that LinkedIn worked by restricting people 's access to you through their invitation approach.  What I'm pretty sure happened here is that the combination of real name + company name + google was quite enough to dig up my email address and to call up my employer and get to my direct line.&lt;br /&gt;&lt;br /&gt;I hate that.  That's not the permission I gave him, and it irritates me that LinkedIn made it possible.  So, I sent a note to LinkedIn customer support complaining about this inappropriate usage.  I'll keep you posted with how that turns out, but it sure seems like it should be in their best interests to keep people from using them to mine other people's personal data.  We'll see how that turns out.&lt;br /&gt;&lt;span id="_user_DPayne@opsware.com" style="color: rgb(0, 104, 28);"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-2371444893277919596?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/2371444893277919596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=2371444893277919596' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/2371444893277919596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/2371444893277919596'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2007/04/linkedin-end-run.html' title='LinkedIn end-run.'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-3215502880423205129</id><published>2007-01-26T10:31:00.000-08:00</published><updated>2007-01-26T11:00:50.582-08:00</updated><title type='text'>When is a property not a property?</title><content type='html'>There's a &lt;a href="http://cafe.elharo.com/java/what-properties-in-java-should-have-looked-like/#comment-51422"&gt;lot&lt;/a&gt; of &lt;a href="http://weblogs.java.net/blog/cayhorstmann/archive/2007/01/properties_are.html"&gt;talk&lt;/a&gt; about property support in Java 7.   Some of the proposals allow you (like C#) to access the get/set methods without using the method name:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;foo.bar  //actually calls Foo.getBar() or a reasonable facsimile&lt;/blockquote&gt;&lt;br /&gt;Except now you've made a distinction between accessing it as a 'property' and accessing it via a method.  What's the difference?  &lt;a href="http://weblogs.java.net/blog/rbair/archive/2007/01/remis_property.html"&gt;Richard Blair says&lt;/a&gt; "read the docs", but I think that's the wrong answer.  The language has made a distinction by allowing two ways to access code that makes multiple modifications to an object's state.  If the distinction is meaningless, then it adds clutter.  Any access to a 'property' needs to appear to be a method call to client code, because that sets expectations accordingly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-3215502880423205129?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/3215502880423205129/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=3215502880423205129' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/3215502880423205129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/3215502880423205129'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2007/01/when-is-property-not-property.html' title='When is a property not a property?'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-2472506696761499312</id><published>2006-11-30T15:38:00.000-08:00</published><updated>2006-11-30T15:47:18.688-08:00</updated><title type='text'>Always and Never</title><content type='html'>The first thing I have to explain to business people when they're trying to give me requirements is that there are two kinds of "never". There's the business/real-world never, and then there's developer never.  What regular people usually mean when they say never is "not very often". &lt;br /&gt;&lt;br /&gt;In order to get the point across, and to clarify what people want when they say "never", I explain the repercussions:  "Okay, you say this never happens.  Is it okay if the program asks the user to contact support and then exits if it does happen?"  That tends to get us to the right answer pretty quickly.&lt;br /&gt;&lt;br /&gt;Trickier is "always".  It has the same problem of being far more precice in software than it is in English.  What's worse is that it's often implied or inferred in an otherwise reasonable requirement.  "The software will send an email when an order is placed."  Is that an always statement?  Asking this question can be very illuminating.  Typical responses can be "Well, not if there's been a problem -- then we want to call."  or "Yes, if they've given us an email address".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-2472506696761499312?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/2472506696761499312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=2472506696761499312' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/2472506696761499312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/2472506696761499312'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2006/11/always-and-never.html' title='Always and Never'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-8594337106677686569</id><published>2006-11-17T10:53:00.000-08:00</published><updated>2006-11-17T14:07:26.233-08:00</updated><title type='text'>Do (our) users want broken features?</title><content type='html'>So, I've completely drunk the testing Kool-Aid.  I've taken it as my personal goal to incorporate automated testing in my entire process, and have seen it work.  I've had multiple releases go through QA with no functional bugs*.  I preach test-first development to everyone that will listen.&lt;br /&gt;&lt;br /&gt;The problem is that our users actually want buggy features.&lt;br /&gt;&lt;br /&gt;This was pointed out to me by some of my coworkers in a code review where we discovered a class that was fairly complex, but had no unit tests.  We talked about why this came to be, and the answer given was that if the project goes to QA but has bugs, nobody gets in trouble.  If it goes to QA, has no bugs, but has fewer than expected features, then the project "slips", people panic, and we have PMs and above at our desks wringing their hands and asking "what went wrong."  The pressure shifts from dev to pump stuff out to QA to give the approval.  And I fall into this trap every time.&lt;br /&gt;&lt;br /&gt;However, I've said "my users", but it isn't my users that are giving me pressure on the release dates.  It's my project management.  Maybe I should say:&lt;br /&gt;&lt;br /&gt;My project managment actually wants buggy features.&lt;br /&gt;&lt;br /&gt;For those of you following along at home, this isn't specific to my current place of employment.  Now that I consider it, I think I've seen this everywhere I've worked.  The only time I didn't feel it was on the two projects where we had a reputation for quality in our QA releases.  I feel like lightning has to strike in order to build up this kind of reputation, and I haven't been able to make a tall enough rod on my current projects.&lt;br /&gt;&lt;br /&gt;What's worse is that we clearly increase the amount of time between when the bug is written and when it is discovered.  That means the bugs take longer to fix, which ultimately means that the project takes longer, even though we've "hit our dates."  This is clearly because there's an expectation of a long time in QA that can't be well estimated.&lt;br /&gt;&lt;br /&gt;I think the Agile folks would suggest that the problem is with "QA resources" in general.  I have a tough time letting go of that specialization.  Test plans are difficult to write well, and even more difficult to execute with consistency and an eye for detail.&lt;br /&gt;&lt;br /&gt;Maybe the right answer for us (if this can't be addressed by talking to the various date-concerned entities) is to not expose a QA handoff date, but incorporate QA into the dev team itself as partners in the ultimate deliverable date.  XP would seem to suggest this as the way to go.  We would have more flexibility (agility?) in giving sections to QA when they're testable, and optimally we could even test things earlier in our cycle than we currently do.&lt;br /&gt;&lt;br /&gt;I worry that some parts of the team leadership may hyperventillate at the idea that there isn't an official QA handoff date that they can track and put a checkmark next to, or put less snarkily, have less information with which to schedule QA resources.&lt;br /&gt;&lt;br /&gt;I still don't know if I can reconcile those needs, but I know that I don't like the behaviors that the current process encourages.&lt;br /&gt;&lt;br /&gt;* functional bugs are what you get when QA says, "should it do this?" and Dev says, "oops, no."  There are tons of other kinds of bugs, like usability issues or miscommunication issues.  Most of those aren't addressed by automated testing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-8594337106677686569?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/8594337106677686569/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=8594337106677686569' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/8594337106677686569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/8594337106677686569'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2006/11/do-our-users-want-broken-features.html' title='Do (our) users want broken features?'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-477672934251258298</id><published>2006-11-14T23:36:00.000-08:00</published><updated>2006-11-15T00:05:21.915-08:00</updated><title type='text'>Phidgets: the Beginning</title><content type='html'>So, I'm a total hardware n00b.  I've written software for a decade, and happy talking about inheritence, encapsulation, polymorphism and tossing around newer buzzwords like dependency injection and all that.&lt;br /&gt;&lt;br /&gt;But I decided to start a hardware project.  I'm not going to give away the ending, mostly because I'll probably never get there.  Remind me to tell you the story about the coffee table I was going to make once.&lt;br /&gt;&lt;br /&gt;Anyway, I bought an 8/8/8 Interface Kit from &lt;a href="http://phidgets.com"&gt;Phidgets.com&lt;/a&gt;.  It's a smallish thing, about the size of a deck of cards, and about a hundred bucks delivered.  It's designed to pass inputs and outputs through USB to a computer, where software running there actually makes the decision about what to do when.  Plus, one of the hojillion languages they support is Java, so that feels right at home.&lt;br /&gt;&lt;br /&gt;I've got the thing on my desk now, and am installing the software.  Except it needs the .net framework, blah blah blah.  It's nice enough to redirect me to the download page, and after getting confused about my 64 bit proc but 32 bit operating system I'm good.  That done, their software installs fine.  While .Net was .downloading I got eclipse set up with their Java examples, and once the software was installed and the device connected their InterfaceKit example ran right out of the box.  Granted, I have nothing hooked up to it, so I don't know if it's doing anything, but it prints lots of stuff to the screen.  I grabbed a wire and jammed it between the ground and the different inputs, and successfully made stuff print to the screen.  Cool!&lt;br /&gt;&lt;br /&gt;Next up is outputs.  For that I have an LED that I clipped off of a defunct printer screen.  I'd have desoldered it, but Nicole just bought the desoldering iron, and I wanted her to be the first to use it.  I hook it up, and nothing happens.  So I hit their website, which has the "n00b manual for InterfaceKit", which is six pages long.  I've read manuals that are 20 pages and have less useful information.  There happens to be a section on "hooking up LEDs to your InterfaceKit", and by section I mean a page.  It mentions anodes and cathodes.  Which I look up on wikipedia, turn my LED around and it works.&lt;br /&gt;&lt;br /&gt;Sort of.  I've written my own software to turn input #1 on for 2 seconds, then off.  The LED responds by shining bright and steady in the "on" state, but instead of being off for the "off" state, it flashes.  I vaguely remember that "digital" outputs have some kind of square wave mojo going on below a certain hobgoblin threshhold or something, but all that information is eleven years old, and there is a lot of beer and parties standing between my CE 101 class and today's attempt.  I also suspect that the answer is actually on the LED page of the manual, but again too much inebriation between those symbols and the present day.&lt;br /&gt;&lt;br /&gt;So, I've got a flashing LED.  The software has been fairly straightforward to this point, and while they don't release the sourcecode to their Java libraries, they do have a reasonably well written Javadoc.  Moreover, to this point things are written in a pretty straightforward manner.  To turn the LED on and off, I've written these lines:&lt;br /&gt;&lt;br /&gt;interfaceKit.setOutputState(1,true);&lt;br /&gt;interfaceKit.setOutputState(1,false);&lt;br /&gt;&lt;br /&gt;(with sleep statements in between)&lt;br /&gt;&lt;br /&gt;So, I'm reasonably sure I haven't screwed that up.  I even have system.out.printlns in between, which of course make me feel dirty, but I'm ignoring that for now.&lt;br /&gt;&lt;br /&gt;I'm not the only hardware n00b connected to the global inter-tubes, so I sign up for their forums.  I could complain about the way the forums insist on mailing me a generated password as though I'm going to be doing stock trading on this thing or something, but that's really just sniping at this point.  I shut up about the password thing, and enter "flashing LED" into the forums.&lt;br /&gt;&lt;br /&gt;No luck there, I think now that the problem has to do with the shoddy wire I'm using (cut out of an old phone cable, stripped with a kitchen knife, and not a solid wire but twisted copper).  I changed the LED to another output, and this time off was off, but on was flashing.  I went to change it again, and dropped the LED off the end of the wire (I just had it wrapped, not soldered or anything), and have decided to declare that to be the problem, and call it a night.&lt;br /&gt;&lt;br /&gt;Next time:  wire strippers and real wire!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-477672934251258298?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/477672934251258298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=477672934251258298' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/477672934251258298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/477672934251258298'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2006/11/phidgets-beginning.html' title='Phidgets: the Beginning'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-116226221095896519</id><published>2006-10-30T18:09:00.000-08:00</published><updated>2006-11-10T15:33:51.565-08:00</updated><title type='text'>Dead Horse: Checked Exceptions</title><content type='html'>I'm reading "Beyond Java", by Bruce Tate, and he complains as many have about checked exceptions.  I've never understood this complaint, and I don't want to say that it's because I understand how to use them and all these smart people don't, but I'm about to.&lt;br /&gt;&lt;br /&gt;I like checked exceptions, they keep me honest.  Tate asserts in many places in his book that the few actual problems that static typing catches would be caught with unit tests anyway, but this seems like a case where you can't make that argument anymore.  In the unit tests I write and read, failure cases are the least well handled.&lt;br /&gt;&lt;br /&gt;Tate (and others) asserts that checked exceptions are invasive, and continues to say that most of the time you can't do anything but throw it, so you're always throwing them, and eventually you just ignore anything you read that has exception in it.&lt;br /&gt;&lt;br /&gt;He's right, about that part.  The problem that I see is that it's never led him to used checked and unchecked exceptions together.  Here's how I evaluate whether to handle, re-throw or convert an exception:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1.  Can I handle it?  Obviously, if I can, I do.&lt;br /&gt;2.  Will callers be able to handle it?  Then let them.&lt;br /&gt;3.  If callers can't handle it, is it imperative (due to data corruption) that callers be aware of this situation?&lt;br /&gt;4.  If none of the above, turn it into a Runtime Exception.&lt;br /&gt;&lt;br /&gt;These questions are asked at integration points, like the barrier between a webapp and the database, a property loader and the filesystem, or a utility program and a webservice.  If we had no checked exceptions, I feel pretty confident that I would fail to consider all the potential failures in these integration points, and have far less robust code as a result.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-116226221095896519?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/116226221095896519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=116226221095896519' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/116226221095896519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/116226221095896519'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2006/10/dead-horse-checked-exceptions.html' title='Dead Horse: Checked Exceptions'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-116199510490727651</id><published>2006-10-27T17:11:00.000-07:00</published><updated>2006-11-10T15:33:51.466-08:00</updated><title type='text'>Selenium rocks the house</title><content type='html'>I'm so impressed with  &lt;a href="http://www.openqa.org/selenium/"&gt;Selenium.&lt;/a&gt;  The browser integration and the IDE true/false makes it very easy to set up and use.  I literally got it working in about ten minutes.  I had a couple of bugs from QA, so I used Selinium to record their replication in my dev environment, then switched a couple of attributes from "off" to "on" to represent what the code *should* do.  And now I'm back to automated test-first programming.&lt;br /&gt;&lt;br /&gt;I see that with the Selinium RC server, I could actually run these things as Junit tests, or I can run them with the selinium suite.  I'm torn as to which way I want to go.  Obviously, recording them via the Selinium IDE is the way to start, but being able to make modules in Java code sounds pretty powerful.  Once you go to Java, though, you don't go back to the IDE, so I'm worried that will make it less flexible in terms of using selinium tests to communicate with the QA department.&lt;br /&gt;&lt;br /&gt;I'm sure that the QA department can learn to use this tool -- they've learned far more byzantine automation tools in the past.  A frequent problem we have is in communicating with the folks that do our acceptance testing.  They're a hand-picked subset of our actual users, and it's often difficult to communicate unusual situations.  The type of bug reports we are typical of non-technical bug reports, basically "got this error" without a lot of information of what happened before the error happened in the first place.  That's not their fault -- they're likely not thinking about what they've done before, and in many cases the problem is so complicated or convoluted that they can't realistically be expected to remember.&lt;br /&gt;&lt;br /&gt;The thing I'm really wondering is if Selinium is simple enough to be used by our acceptance testers to help articulate what they're seeing.  Could we really ask them to just record their session, and playback their experience?  That would be pretty exciting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-116199510490727651?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/116199510490727651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=116199510490727651' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/116199510490727651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/116199510490727651'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2006/10/selenium-rocks-house.html' title='Selenium rocks the house'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-116172602517552773</id><published>2006-10-24T14:37:00.000-07:00</published><updated>2006-11-10T15:33:51.336-08:00</updated><title type='text'>So much less spaghetti code?</title><content type='html'>I talked to a Rails proponent today, who mentioned that he was very tired of all the spaghetti code he was working with in his current development language (Java), and said that working with Ruby and Rails was such a relief.  He espoused this as an attribute of Ruby itself, that it didn't create such spaghetti code.&lt;br /&gt;&lt;br /&gt;I, the skeptic, suggested that the spaghetti just hasn't  been cooked yet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-116172602517552773?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/116172602517552773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=116172602517552773' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/116172602517552773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/116172602517552773'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2006/10/so-much-less-spaghetti-code.html' title='So much less spaghetti code?'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-115758754517019052</id><published>2006-09-06T17:03:00.000-07:00</published><updated>2006-11-10T15:33:51.248-08:00</updated><title type='text'>Rails and the SOA</title><content type='html'>In a nutshell, I'm told that one of the great things about Rails is that you don't have to do all this middleware work to access the database.  It gens up objects and they Just Work (tm).&lt;br /&gt;&lt;br /&gt;Other people talk about how great middleware is:  Create your Service Oriented Architecture as though the database doesn't even exist, and interact with it that way. Do all the ugly database stuff for the back-end of that.&lt;br /&gt;&lt;br /&gt;Is the upshot of this that you should write middleware with Rails?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-115758754517019052?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/115758754517019052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=115758754517019052' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/115758754517019052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/115758754517019052'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2006/09/rails-and-soa.html' title='Rails and the SOA'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-115454588199389950</id><published>2006-08-02T12:08:00.000-07:00</published><updated>2006-11-10T15:33:51.115-08:00</updated><title type='text'>Please choose the site closest to you, because our site is stupid.</title><content type='html'>Why do websites and download tools continue to ask me to choose from a badly-sorted list of locations to decide where I should download from?  Sourceforge and Eclipse both do this.  They're completely capable of asking (and in at least Eclipse's case remembering) where I am, and choosing a site from there.&lt;br /&gt;&lt;br /&gt;Otherwise, I'm left staring at a huge list of locations, some of which are ridiculous (Tel Aviv?  I'm sure I've got a hot connection there), and others are unknowable (UMP?  What does that mean?).&lt;br /&gt;&lt;br /&gt;The whole idea of online updates is that it's easy.  Adding these user-unfriendly steps kind of defeats that purpose.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-115454588199389950?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/115454588199389950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=115454588199389950' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/115454588199389950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/115454588199389950'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2006/08/please-choose-site-closest-to-you.html' title='Please choose the site closest to you, because our site is stupid.'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-115143827368133838</id><published>2006-06-27T12:51:00.000-07:00</published><updated>2006-11-10T15:33:50.929-08:00</updated><title type='text'>Nice goal, what's your plan?</title><content type='html'>Scott Berkun writes today that, in a nutshell, personal goals are amorphous and weird.  He points out that in order for them to be useful, they have to be measurable and specific.  But that's not what goals are.  If you ask someone for their life goals, they'll say things like "retire by 60" or "own my own home" or somesuch.  That's not measurable until it's done.  The illuminating followup question is, "What's your plan to reach that goal?"  If you're talking about your life, and you don't have a plan to reach that goal, then you're not gonna.  The same is true for career goals.&lt;br /&gt;&lt;br /&gt;Let's say your goal is to "master Hibernate".  That's a nice goal, but not at all measurable.  Plan items might be to:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Read a particular book on Hibernate and give a presentation.&lt;/li&gt;&lt;li&gt;Answer (correctly) at least 7 postings in the Hibernate forums.&lt;/li&gt;&lt;li&gt;Apply skills above to map a bidrectional many-to-many relationship.&lt;/li&gt;&lt;li&gt;Research transaction options and give a presentation/recommendation.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Goals without a plan aren't goals, they're just hopes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-115143827368133838?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/115143827368133838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=115143827368133838' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/115143827368133838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/115143827368133838'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2006/06/nice-goal-whats-your-plan.html' title='Nice goal, what&apos;s your plan?'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-111809087186994224</id><published>2005-06-06T11:09:00.000-07:00</published><updated>2006-11-10T15:33:50.769-08:00</updated><title type='text'>Threading .. the next revolution</title><content type='html'>I've been thinking for years that the next major language/runtime improvement to follow automatic memory management is automated synchronization. Not the heavy-handed top-level "synch all" but something that is smart about what needs synchronization and what doesn't. It will have to know about deadlocks and stale reads, and atomicity violations, and prevent them all with reliable accuracy. &lt;br /&gt;&lt;br /&gt;Why this, and why now?  It seems like a logical next step after memory management, and I'm far from being the first to have that notion.  In the last couple of years, however, it's becoming apparent that some of the push for this kind of solution will come from the hardware that our systems are running on.  Industry pundits have been saying that single-core speeds are going to stop increasing. However, this prediction has become real enough now that multi-core single dies and hyper-threading approaches are in production.  To take advantage of these performance increases, you often must change the way your application functions to focus on multi-threaded capabilities.&lt;br /&gt;&lt;br /&gt;Tools that have some of this knowledge already exist, mostly geared towards development-time analysis. What we'll need, however, is a run-time handling of the problem, backed by some kind of language adaptation (either new features, or new usage of old features)&lt;br /&gt;&lt;br /&gt;At first glance, this problem looks a lot like the memory allocation problem. There will be run-time tradeoffs for development time gains. It should simplify the tedious and complicated business of determining where synchronization issues are. It takes a run-time tool (memory analyzers) and turns it into a run-time action (garbage collection).&lt;br /&gt;&lt;br /&gt;However, there's a major difference. Where many developers were willing to put up with an overall runtime slowdown in order to gain an increase in developer efficiency, that won't be the case for automatic synchronization. The entire point of automatic synchronization is to take advantage of the potential performance gains in the new thread-heavy architecture. Add to that the fact that unlike most applications, the runtime synchroniztion must be 100% (possibly needing to be provably) correct, and you have a big task.&lt;br /&gt;&lt;br /&gt;I've said something here that needs elaboration. It is my belief that most multithreaded applications today work, but are not correct. It's been my experience that if you examine a complex multithreaded system closely enough, you are almost guaranteed to find situations where there exists the potential for deadlock or dirty-read issues. In practice, these issues "almost never matter" because of outside guarantees: "That thread never runs when this thread is running" or of timing scenarios that, while possible, are very unlikely. An automated system would not have the luxury of being lucky, and as a result will incur overhead that hand-synchronized systems will not need to handle.&lt;br /&gt;&lt;br /&gt;Speaking of handling, what would it have to handle?  Here's a list of synchronization problems off the top of my head:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;stale thread information&lt;/li&gt;   &lt;li&gt;atomic reads/writes&lt;/li&gt;   &lt;li&gt;deadlocks&lt;/li&gt;   &lt;li&gt;transactions&lt;br /&gt; &lt;/li&gt; &lt;/ul&gt; The last one is the interesting one. It's not enough to have perfect field-level automatic synchronization. You must be able to designate a group of changes as being written atomically. A classic example is a bank balance transfer. The new values in 'checking' and 'savings' must be written at the same time, to prevent any user of the thread from getting a mismatched value. I think this is where new language features, or new usages of old features, are going to drive a new approach to programming.&lt;br /&gt;&lt;br /&gt;Of course, nothing is new under the sun. That 'classic' example of transactions is just like writing to a database. Both operations need to be done atomically to the database, so that if they fail, they fail together. Approaches from relational database programming can certainly be applied here, leading us to think of shared memory like a database. Even so, I don't think there's a standard API or approach to database save transactions currently in wide use across languages, and probably not even within any open language. Closed languages like Delphi and others may likely have a single dictated approach.&lt;br /&gt;&lt;br /&gt;Now, obviously I'm not the first to come up with the idea of automatic synchronization. There are academic papers written 15 years ago or more on the subject. Graph theory certainly has something to say about this kind of thing, and parts of its tenets are even older. There's a lot to read even before getting started, and it's a big project.&lt;br /&gt;&lt;br /&gt;But big projects, in the XP way, should be reduced to smaller projects. So I ask: "What is the smallest amount of the above problem that we can solve, and still be useful?"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-111809087186994224?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/111809087186994224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=111809087186994224' title='96 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/111809087186994224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/111809087186994224'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2005/06/threading-next-revolution.html' title='Threading .. the next revolution'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>96</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-111695844433360025</id><published>2005-05-24T11:09:00.000-07:00</published><updated>2006-11-10T15:33:50.548-08:00</updated><title type='text'>Combining Code Review with Paired Programming</title><content type='html'>Combining &lt;span id="st" name="st" class="st0"&gt;Code&lt;/span&gt; &lt;span id="st" name="st" class="st0"&gt;Review&lt;/span&gt; with Paired Programming:&lt;br /&gt;An approach by Kevin Klinemeier and Charlie Sheppard&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The first rule of the &lt;/span&gt;&lt;span style="font-weight: bold;" id="st" name="st" class="st0"&gt;Code&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;" id="st" name="st" class="st0"&gt;Review&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt;  You don't leave the &lt;span id="st" name="st" class="st0"&gt;code&lt;/span&gt; &lt;span id="st" name="st" class="st0"&gt;review &lt;/span&gt;with more work to do.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The second rule of the &lt;/span&gt;&lt;span style="font-weight: bold;" id="st" name="st" class="st0"&gt;Code&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;" id="st" name="st" class="st0"&gt;Review&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt;  You don't leave the &lt;span id="st" name="st" class="st0"&gt;code&lt;/span&gt; &lt;span id="st" name="st" class="st0"&gt;review&lt;/span&gt; with more work to do.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The third rule of the &lt;/span&gt;&lt;span style="font-weight: bold;" id="st" name="st" class="st0"&gt;Code&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;" id="st" name="st" class="st0"&gt;Review&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt;  If this is your first time, you have to ... uh... listen.  We're not that hardcore.&lt;br /&gt;&lt;br /&gt;&lt;span id="st" name="st" class="st0"&gt;&lt;/span&gt;Code reviews can be stressful, frustrating, and/or a waste of time. This approach attempts to avoid at lot of that by being more like a pair programming session (with keyboard and projector) than a review of a bunch of printed-out code. Take a laptop with your favorite IDE and the latest version of the codebase. Sit down with a group of 3-5developers and pick a few classes to review.&lt;br /&gt;&lt;br /&gt;As you review a piece of code, rather than noting suggestions as tasks for later (see rule #1), actually make those changes to the codebase. If they're too large to be made in a single code review, pare the change down to what you *can* do, and do that. At the end, check in your changes and be done with it.&lt;br /&gt;&lt;br /&gt;This approach tends to be much more interesting for the participants because there's more interaction, and is more productive because you can see your changes made as you suggest them.&lt;br /&gt;&lt;br /&gt;It is important to be serious about the no-extra work rule. This keeps your developers from thinking, "Ugh, we have to go to an hour-long meeting from which I'll gain two more tasks to do this week. Screw that, I don't have time." Sacrifice your changes before you sacrifice the no-extra work clause. Adding extra work in the review causes the review to be skipped in 'crunch time', and ultimately lost along the wayside.&lt;br /&gt;&lt;br /&gt;In general, when you start or amend your code review process, let your developers know that they should expect that they *will* find changes. Nobody is capable of keeping all the possible considerations in mind while they're writing software. That's why we do code reviews, and why paired programming is so powerful. Also, even if your software is very, very well written, you don't put several developers in a room and ask, "Hey, what do you think of this piece of code?" and get "No changes" as a result. It just doesn't happen.&lt;br /&gt;&lt;br /&gt;The last thing, and this is obvious, but be polite. There may very well be a reason the code is the way it is, or even if there isn't (it really is that bad), it's likely the author and the rest of the team already knows better. Laugh at yourselves from time to time, and overall stay positive. Talk more about what can be fixed, rather than problems left behind.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-111695844433360025?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/111695844433360025/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=111695844433360025' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/111695844433360025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/111695844433360025'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2005/05/combining-code-review-with-paired.html' title='Combining Code Review with Paired Programming'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-111695755563309997</id><published>2005-05-24T10:56:00.000-07:00</published><updated>2006-11-10T15:33:50.458-08:00</updated><title type='text'>A Better Mock Objects explanation</title><content type='html'>So, despite my February posts to the contrary, last week I finally understood what Mock Objects are.  Or more directly, I finally understood what they &lt;span style="font-style: italic;"&gt;aren't&lt;/span&gt;.  Martin Fowler's article entitled &lt;span style="font-style: italic;"&gt;Mocks Aren't Stubs&lt;/span&gt; really laid it out well.  Stubs are used for state-based testing.  Mocks are used for interaction-based testing.  Using a Mock when what you want is a Stub generally results in the interaction-testing features getting "in your way".  This is the case for the www.mockobjects.com mock implementation of the various HTTPxxx interfaces.  They add a lot of useful methods for testing interaction, but when all I want is to set attributes, they're "in the way".&lt;br /&gt;&lt;br /&gt;Martin Fowler's Article:&lt;br /&gt;&lt;br /&gt;http://www.martinfowler.com/articles/mocksArentStubs.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-111695755563309997?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/111695755563309997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=111695755563309997' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/111695755563309997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/111695755563309997'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2005/05/better-mock-objects-explanation.html' title='A Better Mock Objects explanation'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-110814568454366722</id><published>2005-02-11T10:00:00.000-08:00</published><updated>2006-11-10T15:33:50.095-08:00</updated><title type='text'>Mock Objects explanation</title><content type='html'>I wrote what I think was a very good explanation of the Mock Objects approach on the junit mailing list today, so I've copied it below.&lt;br /&gt;&lt;br /&gt;One thing I found interesting was the way I ended the message.  I said, "I think Mock Objects are fun".&lt;br /&gt;&lt;br /&gt;What a curious thing to find fun.  It's true, though.  Writing Mock Objects gives me a special kind of gee-whiz satisfaction that I can't exactly explain.  It may have something to do with the fact that writing Mock Objects frequently involves little "tricks" like scoping changes or subclassing and overriding major functionality.  In normal code, I'd consider these tricks to be an abherration and a threat to readability and maintainability.  For some reason, they're acceptable to me in Mock Objects.&lt;br /&gt;&lt;br /&gt;I wonder now if the Mock Objects I've written are horrible monstrosities full of hacks and completely unusuable to those who come after me.  I hope not, and in general I don't think so.  If there's a readability issue I'm worried about it's when I make a mock object than needs to implement just &lt;span style="font-weight: bold;"&gt;one&lt;/span&gt; method out of an interface, and I let Eclipse just code-generate the rest of the class.  Sure, I move the implemented methods to the top, but it isn't exactly clear. &lt;br /&gt;&lt;br /&gt;This seems to raise the question, though:  If my very-clever Mock Objects are maintainable, then why do I hate and avoid this kind of work in my regular projects?  Is it a question of scale, perhaps?  I could (but don't) declare most of my Mock Object implementations as final, nothing subclasses them.  Is it that there is more subclassing going on in my actual project code, and hence more need to keep things simple?  I have my doubts about that as well.&lt;br /&gt;&lt;br /&gt;Perhaps I just need to kill my darlings, but ... they're &lt;span style="font-style: italic;"&gt;so&lt;/span&gt; &lt;span style="font-style: italic;"&gt;cute.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;-Kevin&lt;br /&gt;&lt;br /&gt;The original text:&lt;br /&gt;&lt;br /&gt;Often, many of the inputs and outputs of your system are its interaction with other classes.  Those classes frequently have states or take actions that are difficult to test (sniffing packets, throwing exceptions). &lt;br /&gt;&lt;br /&gt;In order to avoid this problem, you use a class that appears to your unit under test as though it is the tool it usually calls, but under the covers you've stripped out its functionality and replaced it with something you can test with.&lt;br /&gt;&lt;br /&gt;Let me assume that in your example, you pass in some kind of network-access object in your constructor, which is then used by various methods.  You need to test what your code does when that network object reports that it cannot contact any network at all.  This is a very difficult situation to simulate with the actual code.&lt;br /&gt;&lt;br /&gt;You create (or if you're lucky, download) a class that subclasses your network access object.  That class may be called "AlwaysFailingMockNetworkAccessObject".  It is bone-stupid, and is in actuality not a network access object at all.  The only thing it does is fail when its access methods are called.&lt;br /&gt;&lt;br /&gt;So in your test, you construct your class with this AlwaysFailingMockNetworkAccessObject, and then make your assertions about your class' behavior.&lt;br /&gt;&lt;br /&gt;Another test might use a PlaybackMockNetworkAccessObject (another class I made up).  This object might not contact a network at all, but accept in its constructor a set of data to return as though it came from a network.  Using this, you can write a set of assertions based on a set of data.&lt;br /&gt;&lt;br /&gt;One common first reaction to the Mock Objects approach is that "It doesn't *really* test the system" since it doesn't involve some major component.  This is when Unit Testers reply, "It tests everything I'm concerned about -- I don't need to test the Network Access implementation, it isn't my problem."  You'll also be doing an integration test before you release.  This, however, is a unit test, and the Mock Objects approach helps you test just your unit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-110814568454366722?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/110814568454366722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=110814568454366722' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/110814568454366722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/110814568454366722'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2005/02/mock-objects-explanation.html' title='Mock Objects explanation'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-110722483371308244</id><published>2005-01-31T18:05:00.000-08:00</published><updated>2006-11-10T15:33:49.981-08:00</updated><title type='text'>Puzzle Pirate Banker</title><content type='html'>I wonder if this would be a viable mini-business in &lt;a href="http://www.puzzlepirates.com"&gt;Puzzle Pirates&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;The "system" (aka the man) charges you a 10% or so fee to transfer your poe between islands. This fee goes up if you want to transfer between islands in different archipelegos.&lt;br /&gt;&lt;br /&gt;Could a player or group of players who have significant idle holdings undercut this practice?&lt;br /&gt;&lt;br /&gt;The problem is that the poe needs to get there. Either via an able crew, or just general accumulation, let's say for the sake of argument that the poe is at several locations arleady.&lt;br /&gt;&lt;br /&gt;One could create a website (that is updated -- the not fun part) that knows how much poe is where. Users can enter the place their poe is and where they want it to go. The system will then tell them how much they can transfer (the lower of the poe onhand at those two destinations), and the fee.&lt;br /&gt;&lt;br /&gt;The player would then have to arrange a time to meet with a trusted broker to close the deal.&lt;br /&gt;&lt;br /&gt;Building trust is obviously an issue, as the broker cannot trust the customer. Ingame events like auctions and such should be enough to get the ball rolling. False accusations of fraud from dishonest players will be a problem, especially if they occur while the system is getting started.&lt;br /&gt;&lt;br /&gt;It may be that the majority of transactions serve to centralize the poe, or worse, &lt;span style="font-weight: bold;"&gt;de&lt;/span&gt;centralize it to where it is scattered and not useful. Talented sailors will then have to be enlisted. Perhaps the sailors could be commissioned, without the need to trust them implicitly. If there exists a general trust in the organiztion, it could itself advertise for "poe delivery", paying a percentage on the income, perhaps at either isle. This percentage would need to be at least 5% lower than the 'transaction rate' charged to customers.&lt;br /&gt;&lt;br /&gt;Scale is a problem, as a system of trust would need to be created among the brokers. However, once established, brokers could operate as independant agents to a large degree. They can maintain their own network of poe, post their own bounties for poe deliveries, etc. Indeed, they must maintain their own poe, as no-one can be trusted with the "communal pool". To this end, they will need to make their own deliveries. If agents are competing with each other to make transactions, this will tend to ensure that deliveries are as timely as possible.&lt;br /&gt;&lt;br /&gt;Trust could be "ensured" by requiring new agents to provide a "Security Deposit". Agents are then allowed to make transactions up to their security deposit. This provision could be removed for longtime agents. Dishonest players, however, can abuse agents by falsely reporting fraud (certain to happen). This will be indistinguishable from actual fraud.&lt;br /&gt;&lt;br /&gt;Agents would be easier to trust if the poe were paid to a central system rather than the agent himself. Perhaps deposits on private sloops or somesuch can be arranged. This would necessitate an investment of purchasing sloops for each new 'source'. Except that doesn't help at all. Dishonest agents can simply falsely report delivery of the poe and collect the replacement payment and their fee.&lt;br /&gt;&lt;br /&gt;Is there any way for the agent to "prove" the transaction took place? Screenshots can be faked, chatlogs are laughable. Banking data is private. Perhaps ships can again be helpful? Their transaction logs can show who took the poe and how much, though poe can only be removed by crewmembers. A pirate may only be in one crew at a time, and the customer may not have the ability to add the Agent, nor the inclination to leave his crew to receive his shipment.&lt;br /&gt;&lt;br /&gt;These troubles would be acceptable for large amounts (10k+ perhaps), and perhaps the risks are minor enough to dispense with these precautions for smaller amounts.&lt;br /&gt;&lt;br /&gt;This entire idea could be expanded to any type of commodity, actually.  Storage of anything but poe is difficult, however.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-110722483371308244?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/110722483371308244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=110722483371308244' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/110722483371308244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/110722483371308244'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2005/01/puzzle-pirate-banker.html' title='Puzzle Pirate Banker'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10538439.post-110721634228324377</id><published>2005-01-31T15:51:00.000-08:00</published><updated>2006-11-10T15:33:49.833-08:00</updated><title type='text'>Alpha</title><content type='html'>Welcome to my head. &lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10538439-110721634228324377?l=zipwow.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zipwow.blogspot.com/feeds/110721634228324377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10538439&amp;postID=110721634228324377' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/110721634228324377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10538439/posts/default/110721634228324377'/><link rel='alternate' type='text/html' href='http://zipwow.blogspot.com/2005/01/alpha.html' title='Alpha'/><author><name>Kevin Klinemeier</name><uri>http://www.blogger.com/profile/14252101123112180153</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
