| Exploring Solution Spaces © Copyright 2003-2006, by C. Keith Ray | ||||||||||||||||||||||||||
|
Archives
Subscribe |
2005.Dec.17 Sat
On Looking for the Next Microsoft
A good tidbit a long piece by Paul Graham. 2005.Dec.14 Wed A bit more on the Humane Interfaces and Minimal Interfaces debate that I blogged about previously. Some people think XP's "YAGNI"(You Aren't Going to Need It) rule that prevents unnecessary work means XPers are in favor of Minimal Interfaces, but that is only to start with. Refactoring away code duplication (and other code smells that the Simplicity Rules are against) tends to create Humane Interfaces. For example, if I was doing test-driven development in an environment that didn't already have a list class, and one was needed, I would test-drive a minimal implementation: maybe all it has to start with is list.size(), list.at(int index), list.add(object), and list.removeAt(int index). However, as the list gets used, I would look for duplicate code. If I refer to the first element using list.at(0) in more than one place, adding list.first() to the list class would remove duplication (the OnceAndOnlyOnce part of the Simplicity Rules). If I have code like this...
... I don't even need duplication to want to refactor that piece of code into a method of the list class. You'll note those three lines of code have the code smell "Many messages to the same object from the same method" (3 is "many" here), or "asking instead of telling" (we need some pithy standardized names for code smells). Refactoring that code into "list.last()" follows the Simplicity Rule "Expresses every idea that we need to express" (aka "Self Documenting Code", aka "Intention-Revealing Code"). Similarly if I search the list, enumerate the list, and so on, the rules of Simple Design would require that I move those features into the list class as well to clearly express intention and avoid duplication. So as the project progresses, the list class moves from being a very minimal interface to being a humane one, without ever having a method that isn't used in the project. Library(framework) design often starts in a vacuum, but wise people recommend using the library in three non-trivial applications before publishing it, precisely so that these kinds of refactorings can "tune" the library into something people will want to use, before publishing it. 2005.Dec.07 Wed
Minimal versus "Humane" Class API Design
Interesting stuff about class API design: good: HumaneInterface.html doesn't get that intention-revealing interfaces are good, "tell, don't ask" is good, and code duplication is bad: cafeaulait reaction to the above: cincomsmalltalk.com/blog/ Don't forget to read the comments. My comment:
more reactions: simplicity rules in the right place java net style vs smalltalk ruby style (though I'm not sure I agree with 437 methods for Smalltalk's Object Class!) 2005.Dec.04 Sun
Test Duration < Iteration Length
Extreme Programming is built on the assumption that completely testing the product under development can be done within a single iteration. If manual testing is the only method of testing, the test-duration will get longer every iteration until it can't be done within a single iteration. This is why automated testing is so important on an XP project. In well-run XP projects, automated testing covering every feature can be executed, at worse, overnight or in one or two days, and at best, as quickly as 20 minutes or faster. And that's two layers of automated tests: programmer/unit tests, and customer/acceptance tests. The reason XP has iterations and automated testing is to increase the speed of feedback on the design. On a large project, a design that meets all the requirements is going to require a long time to be developed. No person or team can come up with an "instant" design for all the requirements. In a phasist approach, a team might spend a long time coming up a design that they think will meet all the requirements, and not have any real feedback on the goodness of that design until they start implementing it and testing it. If it turns out the design is bad, the project may not have enough time to fix the design before shipping deadline. Contrary to some popular misconceptions, XP team do design, but they do it incrementally, creating tests for that design in each iteration. The implementation for that design isn't considered complete until it passes all the tests that the programmers (doing test-driven development) and the testers (creating customer/acceptance tests) think up. Most importantly, refactoring is design, as the design that was appropriate for the last iteration is changed to be appropriate for the current iteration. Fortunately for people doing incremental design work with refactoring, most automated tests do not have to change when the code is changed. The tests are acting as executable specifications for the requirements, so if the requirements haven't changed, then the tests should not have to change. Of course, when the tests are very close to the implementation, they do sometimes need to be change, but the majority of tests should not change when someone need to alter the design to handle requirements being address in the current iteration. If someone is making changes to the code, and the tests fail, or the code isn't even executable or compilable any more, they are not doing refactoring. They are doing something else, like rewriting, Stop them. Teach them how to do refactorings that are in Martin Fowler's book: each refactoring is a small behavior-preserving change that keeps the code and tests working. Run the programmer tests after each refactoring for assurance that no behaviors have been changed unintentionally. Many people are using refactoring tools that can do refactorings that are almost always error-free, though running the tests is still recommended, just in case. Manual refactoring is more prone to error, so be careful and work slowly in order to avoid mistakes (and therefore go faster). Make sure the whole team knows the direction the refactorings are headed in, so you don't get into cycles where one developer undoes the refactorings of another developer and vice-versa. Teams that haven't gotten their specification and testing processes firmly in place will experience what Michael Feathers calls iteration slop and "trailer-hitched QA":
What happens when there are conflicting requirements? In a large project, it's often hard to detect conflicting requirements because you just can't hold them all in your head at the same time. You could spend some time comparing every requirement to every other requirement, but that's tedious and you're still likely to miss the conflicting requirements -- particularly when some requirements are (as yet) unwritten and/or "derived" requirements. On projects without fast automated tests, conflicting requirements show up as a cycle of bug reports, often with long delays between bug reports. Fixing one bug causes another bug to show up, perhaps weeks later when testing gets to that conflicting requirement. Fixing that other bug causes the original bug to re-occur -- but it may be flagged as a new bug if no one reviews the old "fixed" bugs before filing a new bug report. When every high-level requirement is written as an automated customer/acceptance test, and every low-level requirement is written as a programmer/unit test something interesting happens: getting one conflicting requirement/test to pass will cause another test to fail. Getting that other one to pass will cause the original one to fail. If you run all the tests often, and they run quickly, it becomes pretty obvious that a cycle is going on. Many XP teams create new tests whenever they are going to fix a bug. The test fails because of the bug, and will pass when the bug is fixed. In practice (particularly with legacy code), this can be very difficult because to write a failing test, you first have to find the buggy code. However, having that test in place will help detect conflicting requirements if you later fix a bug and cause the previous bug-detecting-test to fail again. What do you do with legacy code? You can segregate it: do test-driven development on new code, avoid changing the old code, move old features into the new tested-code gradually until the legacy code disappears. This assumes the legacy code is mostly bug-free. If you have to fix bugs in legacy code often, your best strategy is to put the old code under test, starting with the parts you are about to modify for bug-fixes. See Working Effectively With Legacy Code by Michael Feathers for techniques on how to introduce testability into legacy code. You will also have to spend more time on manual testing, and probably have to have longer iterations in which to do it. 2005.Dec.03 Sat"Some of my smartest graduate students get freaked out when they discover what our lives are really like. [...] They think science is about asking questions and devising experiments that answer them. They think there is a map to knowledge they can follow by just working hard. But the truth is that we often don't even know what the right questions are. There is no map. Some of my students get so disoriented by this that they have to quit and do something else." -- Jerry Leob, quoted in Rebuilt: how becoming part computer made me more human by Michael Chorost. 2005.Dec.01 ThuThe title of this post is taken from a spam - I thought it sounded like it should be a real word: medication + boon. Check out Kevin Lawrence's tale of a class that "just" was going to represent a class-name, and became so much more. He titled his post "Fight Complexity with Complexity" but by creating an abstraction that centralizes stuff that was spread out everywhere, he actually simplified the code -- according to two of Kent Beck's rules of simplicity: "no duplicate logic" and "expresses the programmer's intentions".
Utility Functions as a Code Smell
Bunches of utility functions, whether bunched together in a "utility class" or not, are often a sign that code isn't object-oriented enough. For example, in Apple's Cocoa implementation, there are a bunch of utility methods for filename-manipulation, in class NSString:
These path-component methods are actually added to the class NSString via a class category, but are viewed as members of the NSString in the documentation and usage. My point here, with this example, is to raise the question: what are these "path" and "path component" methods doing in class NSString? Perhaps they should be members of a PathName or PathComponent class. (And by the way, pathnames in MacOS X not just unicode, they are "decomposed" unicode, so don't forget to call decomposedStringWithCanonicalMapping; a PathName class would take care that of that for you.) Like pathnames, URLs are strings with rules for how they are formatted, encoded, etc., so you might expect that Cocoa deals with them using a bunch of utility methods in NSString. But, being a later addition to Cocoa, they are actually their own class: NSURL. This class encodes the requirements of RFCs 1808, 1738, and 2732. It provides methods to access host, get the base URL, test if the URL refers to a file, get absolute and relative forms of an URL, and so on. Apple is moving to using NSURLs instead of pathnames in various Cocoa APIs, and beginning to deprecate the pathname-based APIs, since NSURLs can refer to local files as well as remote web-based resources. If you've got a bunch of utility methods, look at their names and behaviors to see if they really belong to one or more new classes. If they conceptually belong to an existing class that you can't edit, Objective-C gives you the option to extend that class via a class category. In other languages, you might have to make a subclass, or in the worst case, leave them as utility methods, but put them together in a class that reflects where you would rather put them. For example, if you write a bunch of string utilities in Java, you can't extend the java.lang.String class, so put them as static methods into your own com.yourcompany.StringExtras class. But first, consider if they are actually representing a concept that deserves to be its own class, like Apple did with URLs. Kent Beck Podcast/Interview here 21 minutes. 2005.Nov.28 MonThis is an partial example of how a story-card might be 'translated' into FIT tests -- this example is paraphrased from the middle chapters of "FIT for developing software" by Mugridge & Cunningham. Here's a story card: +--------------------------------------------------------+ | CreateRentalTemplate | | | | A rental template defines a list of rental items. The | | template specifies the proportion of each item per | | person. The user can select a template and specify the| | number of people to rent those items. | | | +--------------------------------------------------------+ To accompany the story, there is discussion (verbal, spoken) between the programmers, testers, and the person that understands the requirements: the "Customer" in XP terminology, "Product Owner", "Domain Expert", etc. I'll leave out estimation and scheduling of stories, which are taken care of by Release Planning and Iteration Planning. In the case of this story, there is discussion of how rounding-up will occur when the number of people specified doesn't exactly match the proportions in the Rental Template, so the test is written to use numbers that test the rounding-up. Using FIT or Fitnesse, one acceptance test for CreateRentalTemplate would look something more or less like this: -------------------------------------------------- | Create rental template | Coffee break | -------------------------------------------------- | one | coffee dispenser | for | 20 | people | -------------------------------------------------- | one | coffee table | for | 40 | people | -------------------------------------------------- | one | cup | for | 0.9 | people | -------------------------------------------------- -------------------------------------------------------- | begin transaction for client | Joanna | -------------------------------------------------------- | fill template | Coffee break | for | 21 | people | -------------------------------------------------------- | pay cash | 65.00 | -------------------------------------------------------- | end transaction | -------------------------------------------------------- | rentals of client | Joanna | ------------------------------- | rental item | count | ------------------------------- | coffee dispenser | 2 | ------------------------------- | coffee table | 1 | ------------------------------- | cup | 24 | ------------------------------- The code to make this work would involve implementation various kinds of fixture classes, that will be instantiated by the FIT framework, and which in turn call the model objects to exercise the application. Initially the FIT tests will fail because the model objects do not exist or do not yet have required functionality. Use test-driven-development to create the model objects with the required behaviors. Then the FIT tests should pass. See http://fit.c2.com/ for info about FIT, see http://fitnesse.org/ for info about Fitnesse. 2005.Nov.12 SatI'm back from the AYE conference. Very informative. Very interesting (people and sessions). Very intense. Very tiring. Veni Vidi Very. I came back with new books, lots of hand-outs, notes, and a head-cold. No t-shirt. I will be blogging about the sessions and the books as I recover. 2005.Nov.11 Fri
Gates vs Jobs in Slide Presentations
Comparison of Steve Jobs's and Bill Gates's slide presentations compared here:
With pictures. Check it out. 2005.Nov.06 SunQuotes from Lasse Koskela: 2005.Nov.04 Fri In pursuit of better health, I have spent literally hours today waiting for a doctor, a chiropractor, a lab tech, and a pharmacist to do what they do, and even more hours driving from one place to another. The doctor was a last-minute appointment, and the lab work required a waiting period to measure certain biological processes correctly. Also if the prescription had been faxed to the pharmacy like usual, there would have been less of a wait there. There was also some time spent looking for an certain doctor-recommended over-the-counter medicine at a combined grocery store/drug store, which didn't carry it, and at a "real" drug-store, which did carry it. Each place I visited may have been very efficient from their own perspective, but all these wait, search, and transit times are signs of inefficiency from my perspective. (See "Theory of Constraints" for more on that.) This situation is not likely to change as long each of these functions is an independently-owned enterprise, and our laws and traditions will work to preserve this independence at a cost of (my) efficiency. If I valued choice less and efficiency more, I suppose a good HMO (or equivalent) with centralized infrastructure would make for a better experience. (Or maybe not.) 2005.Oct.27 Thu
The Return of Freedom of the Press
Today's quote on my google home page is "Freedom of the press is limited to those who own one." - AJ Liebling. In the days of the USA's founding fathers, anyone who wanted to get their views across to other people would hire a press, or rent or buy one, and print their own pamphlets and broadsides to distribute or sell. It was fairly democratic for that time. In the days of television, only a very few could afford to buy television time. Broadcasters could refuse to show material they disagreed with. The common people had to resort to creating newsworthy "demonstrations", marches, speeches, etc., and hope that a sound-byte would be get broadcast by a news organization. Writing to newspapers and magazines also depends on the whim of editors as to whether your views get published. Now just about anyone can buy or rent a web-page, or even get a free page for a blog, to get across their views. Popular or controversial content shows up on search-engines if enough people agree or disagree with it and link to it. We aren't dependent on the whims of TV or newspapers editors anymore. Power to the people! Yay!
You know, we ought to have a national holiday to celebrate our freedoms of speech and press. 2005.Oct.26 WedQuotes from Charles Petzold's Does Visual Studio Rot the Mind?: (bold-facing is my emphasis) 2005.Oct.24 Mon The most common attitude about test-driven development and user-interface code is that the two don't combine well. I have only attempted a small amount of test-driven UI code - on MacOS Carbon and Java Swing - and didn't find it terribly helpful. I may try again with Cocoa and see how that works out. The danger of having GUI code as a coding-area designated "not to be test-driven" is the temptation to write the GUI code first, and to mix in business logic code with the GUI code. Avoid that temptation. Your business logic could have multiple user-interfaces: a Mac UI, a Windows UI, a Unix/Linux UI, a command-line interface, a scripting UI via COM on Windows or AppleScript on MacOS X, or an embedded scripting language, and even a web-interface. Using FIT/Fitnesse means that you also have an acceptance-testing interface. Keep the UI from mixing with the business logic by test-driving the business logic first. This makes writing portable, multi-platform code much easier since UI code is very often single-platform. Even if you don't plan on writing portable code, TDD-ing the business logic before coding the UI still provides a separation of concerns that is a hallmark of good design, and allows better re-use of the business logic within the same project or different projects. Therefore, to avoid mixing business business logic with the GUI code and thus creating code that's unnecessarily coupled and non-cohesive, test-drive the business logic code first, and write the GUI code last. Sometimes a spike might be necessary to find out what the GUI framework requires. Don't forget to throw away the spike code after you discover what you need to learn. 2005.Oct.17 MonBDUF (big design up front) is not the "opposite" of incremental design, it's part of the continuum of how much design precedes coding/refactoring. In a blog entry where Joel wrote a specification up-front contrasting it with his straw-man view of XP's incremental development, he called what he did BDUF, but it was neither Design (it was specification), nor was it big; he was not doing BDUF, and he was doing something many agile methods promote: creating a specification of the requirements before development. In XP the details of the specification would be delayed until later, but the overall requirements are needed to estimate the Release Plan. Waste does not mean failure. Advocates of incremental design say that too much design up-front is wasteful, but that doesn't mean up-front design can't be part of a successful project.
BDUF is not the same as "too much" design up-front, so stop saying BDUF when you mean TMDUF (too much design up-front). 2005.Oct.10 MonRobert C. Martin writes on the benefits of TDD-style unit tests (bold-facing is my emphasis):
Robert C. Martin compares test-driven development to double-entry bookkeeping:
Robert C. Martin reminds us: 2005.Oct.06 Thu The few people who were doing Waterfall development successfully were offended when proponents of Agile methods attacked the usual attempts at a process also called Waterfall as being unworkable. Both sides were using the same name, but for the most part were talking about different things. Now Ken Pugh's book Prefactoring is out, and he does the same thing: attacking something that many inexpert teams do, but which experts don't (usually) do: stopping progress in a project in order to do a large redesign. He calls that refactoring, a term commonly mis-used for that very thing, but which doesn't fit the definition of refactoring as understood and practiced by the experts. Recall that the first XP project with Kent Beck and Ron Jeffries did the same thing: they spent a week or two with acceptance tests failing as they stopped progress to change a core part of their design. It seems like every team doing XP has to learn the hard way that refactoring has to be done as a continuous process, otherwise code-debt piles up until a big overdue change has to be done. Looking at the sample chapter available from O'Reilly, I see Ken advocating the same care with domain-driven design that many agile experts have advocated. Compare this with, for example, what Kevin Rutherford writes: "One of my current bug-bears is the lack of design done by agile teams. I know we all chant 'design is good, so we design all the time', but in reality it just doesn't happen. Switching from legacy habits into test-first thinking and good object design is a really hard jump." And John Roth: "...the fundamental language types, and the basic language libraries, do not, and let me repeat that, do not represent any concepts that your application actually needs. At best they represent bizzare oversimplifications of those concepts that can't be told apart by the type checking mechanism.". Ken Pugh, in this book, wrote: "...avoid using primitive data types. Pretend that ints or doubles do not exist.... Items are priced in Dollars.... The time for a single song... could be stored in a TimePeriod.... A U.S. Zip Code is not just a CommonString either. You can describe it as a NumericString.... as a FormattedString.. or as a ZipCode data type. If any combination of digits was valid, using NumericString or FormattedString might be appropriate. However, declaring the attribute as a ZipCode type allows us to abstract away its actual representation.... Do not combine classes simply for implementation purposes. You can define both SocialSecurityNumbers and PhoneNumbers as strings of digits with two dashes. That does not make them equivalent.... You would never send a Social Security number to be dialed, nor would you attempt to record payroll taxes against a phone number." I had the opportunity to review a draft of Ken's book early this year, but lost track of it with my new job and all sorts of things. I will not judge his book by the cover, but by its content, which seems to have some uncommon "common sense". 2005.Oct.04 TueAutomated acceptance tests are specifications in an agile method. Check out Dave Churchville's blog entry on this subject. Quote:
Since TDD - Test-Driven Development - is a design-implement technique that happens to produce suites of automated tests, people often think it all about testing. BDD - Behavior-Driven-Design - attempts to correct this by using different terminology. See Elizabeth Keogh's blog entry on this. Quotes: 2005.Oct.02 Sun
Fighting Urban Legends about Garbage Collection
Urban performance legends, revisited, by Brian Goetz. Quotes: 2005.Sep.30 Fri Object-Oriented programming, and design patterns in particular, help us get away from the morass of spaghetti-code from olden days of yore (before OO and design patterns). Imagine a ball of tangled cooked spaghetti that's cooled and congealed and maybe has been sleeping in the freezer for a long while, and you want to remove one stand without breaking any other strands or even moving them too much. You can't: that's tightly-coupled. Here are a few things that couple code: global variables, global functions, concrete classes that refer directly to each other, code duplication, data duplication, C/C++ include files. And "manifest types". That last one is where your programming language requires you to declare type for each member variable, parameter, function result, local variable, etc. And then the compiler checks them. Sometimes you know more than the compiler does and therefore you have to use type-casts to tell the compiler the correct type. The worst of manifest typing and "include files" often goes together. You change the return type of a method from "unsigned short" to "short" (or vice versa), perhaps by changing a typedef for that return-type in a header file. Now every source file that includes that header file has to be recompiled, even if they didn't use that type or that method. Also, every method that overrides or calls that method has to be recompiled - and the rest of each class's code gets to be recompiled as well, even though other methods in the class might not be affected. Every class that has a member variable of that typedef has to be recompiled. Every other method that has parameter or local variable of that typedef has to be recompiled. In this case, the size of the type hasn't changed, the operations that legal for that type haven't changed, and though the range of values used for that variable have changed, almost all the code involving that type will not have to change, but massive recompiled has been forced on you. The same kinds of cascades of recompiling can occur when changing a method's argument type to 'const', or changing from one container type like 'list' to 'vector', or many other things that you would hope would have only minor effects. On large projects, those recompiles can cost hours each day. David Buck talks about this on this blog. He references Local Change / Local Effect Principle and Domino Effect. 2005.Sep.28 WedI once needed to make three "filters" works. They each took an image file and several parameters as input, and produced an output PDF file. For most manual tests for various parameter settings, they did not produce correct output. So I refactored the big filter function to do the filtering in two steps (two subroutine calls). The first subroutine works on the parameters to compute the values needed to be passed into the image processing library, and the second subroutine calls the image processing library with the input image, those computed values, and produces the output image. Then I wrote a parameterized unit test that took all the parameters as input to the first subroutine, also took into expected output values, and asserted that the actual output values were equal to the expected output values. Then I wrote 900 one-line unit tests to this parameterized unit test with the various permutations of the input parameters and expected output values. (I actually worked in a spreadsheet for a while and copied-pasted from the spreadsheet to the unit test source code.) The test would also generate the output PDF file, which I could visually examine About 80% of the tests failed. Then I started working on the first subroutine to fix its problems. I got to where only 60% of the tests failed, then only 50%, 30%, 25%, 10%, the only 2 failures, and then 100% passing. Sometimes a change causes more tests to fail than before, and I could examine my latest modification and fix it, or undo it to try something else. That was the first of the three filters. The other two were similar, but with fewer parameters and options, each of those only needed about 600 one-line unit tests. Note that I didn't test EVERY combinations of options and settings. That would have required several billion test cases. By making an intelligent selection of the "input space" I could exercise the filter algorithm along all of its dimensions with a minimum of effort. Fixing all three filters with the aid of automated tests only took a few days each. Trying to make the algorithm work with manual testing would have taken months or years. Ruby, calling a method with a block argument:
anObject.methodTakingBlock { someObj.doSomethingHere }
or
anObject.methodTakingBlock do
someObj.doSomethingHere
end
Smalltalk, calling a method with a block argument:
anObject methodTakingBlock: [ someObj doSomethingHere ].
Ruby, implementing a method that takes a block argument (the lack of a named block variable and the "yield" keyword are a bit confusing, particularly if you associate "yield" with threads, which are not in play here.)
def methodTakingBlock
yield
end
Smalltalk, implementing a method that takes a block argument.
methodTakingBlock: aBlock
aBlock value.
Ruby, calling a method with a block argument that takes two argument itself:
anObject.methodTakingBlock {
|aVar, bVar| someObj.doSomethingHere(aVar, bVar) }
or
anObject.methodTakingBlock do |aVar, bVar|
someObj.doSomethingHere(aVar, bVar)
end
Smalltalk, calling a method with a block argument that takes two arguments itself:
anObject methodTakingBlock: [ :aVar :bVar |
someObj doSomethingHere: aVar andHere: bVar ].
Ruby, implementing a method that takes a block argument, giving the block the values 12 and 13 for the block's own arguments.
def methodTakingBlock
yield 12, 13
end
An Ruby alternative syntax where the block argument is converted to a Proc object and is accessible via a named parameter:
def methodTakingBlock(&aProc)
aProc.call(12,13)
end
Smalltalk, implementing a method that takes a block argument, giving the block values 12 and 13 for its own arguments.
methodTakingBlock: aBlock
aBlock value: 12 value: 13.
2005.Sep.24 Sat
Dear Wil Wheaton (an Open Letter)
I've enjoyed your books, your blog, and your performances on Star Trek Next Generation. In Dancing Barefoot I particularly enjoyed the story of "William F-ing Shatner" and everything that led up to your epiphany at the Las Vegas Star Trek Experience. In the course of that writing, you mention that Deep Space Nine is not one of your favorite Star Trek series [please don't stop reading yet]. I suggest this may be, at least in part, because you are viewing that show as a Star Trek fan. If you view it as a writer and actor, you may see more value to that series. The meat and potatoes for writers and actors is conflict, drama, and comedy. The setting and cast of DS9 is just full of opportunities for conflict, drama, and comedy. The original Star Trek and Star Trek: The Next Generation were more about exploration and sense of wonder (and there's nothing wrong about that). All of the Star Trek shows (except for the Original Series) took at least two seasons to find their "tone", so please don't judge DS9 from its earliest episodes, which may have started even rockier than the others. DS9 has conflicts in its initial setting: The Bajorans, who were until recently oppressed by Cardassians, have to rebuild the world and rebuild their world-view. They still must interact with Cardassians, and each race hates each other, but in many episodes they have to work with each other, and sometimes even come to love each other. Neither race particularly likes the Federation. Many of the Bajorans now involved with governing the planet and the space station were, quite frankly, terrorists during the Cardassian occupation. I sometimes wonder how this show would play in the Middle East if translated into Arabic, Farsi, etc. Would the viewers think of the Cardassians as representing the United States and/or Israel? I imagine they would identify with the Bajorans to some degree. What would the Federation, with its acceptance of tolerance and diversity, represent to them? Watching the show with those ideas in mind provides a twist quite lacking in most episodes of other Star Trek series. Ben Sisco, the Federation man in charge of the space station, considers himself a man of science, and yet finds himself thrust into the role of the Bajoran "Emissary of the Prophets", a religious figure of much importance, in the first episode. During the seven years of the series, he grows into that role. In the early seasons, he calls the mysterious occupants of the wormhole, the "wormhole aliens," and in later seasons more and more often refers to them using the Bajoran term "the Prophets". His dual 'roles' provide conflicts on both professional and personal levels. Like Wesley Crusher on ST:TNG, there is a child growing up on the show: Jake Sisco. Unlike Wesley, he's something of an under-acheiver. Jake has a particularly moving episode in Season 4 where he loses his father to a "wormhole inversion"; he spends his life trying to retrieve his father from this anomaly, and as an old man, realizes that to save his father, he has to kill himself the next time his father temporarily re-appears. And he does! This resets time back to the original incident and Ben Sisco is able to avoid getting trapped in the time-vortex the "second time" around. Nog, other 'child' on the show (which under the makeup I think was played by an adult), starts outs as a truant who often gets Jake into trouble, and ends up becoming an over-enthusiastic Star Fleet cadet and ensign. He has a episode that is also a good character study in Season 7 where he has to come to terms with losing his leg in the war. You don't really see this kind of character growth in individual episodes; you have to view each season as if you're reading a novel. The best dramatic Season 6 episode shows us what life as black science fiction writer of the 1950's might have been like. Avery Brooks portrays a man with a dream, nearly broken by racism, so well that I'm getting misty-eyed just remembering it. Far Beyond The Stars should have won mainstream awards for best TV series dramatic episode, but of course it wasn't considered because it was "just" a science fiction show. :-( There are too many good dramatic episodes to list (poor Chief O'Brien, the "everyman" character: he gets himself wrung through the wringer many times ), but I also love the comedic episodes. The Ferengi, who are mostly used for comedic episodes, poke fun at our capitalistic society. The season 6 episode, The Magnificent Feregni , is one of the funniest because they try to act all macho, which is out of character for their kind (though Quark, Rom and Nog demonstrate honor and quiet bravery in many dramatic episodes). The House of Quark in Season 3 , where Quark temporarily marries a Klingon and saves her house through good accounting and Klingon-esque bravery, is also particularly good. Perhaps the best comedic episode of all builds on the Original Star Trek's The Trouble With Tribbles : Trials and Tribble-ations . For a Star Trek fan, this episode is a must-see because of how detailed their recreations of the original ship model, sets, costumes, and props are. Watch the DVD's "making of" extras to see how much love went into the making of that episode. DS9 probably brought back more actors reprising the characters from the original series than any other. (But they were all Klingons!) "Darvin" from Tribbles, "Kor", "Kang", and "Koloth" in other episodes. So there something there for a Star Trek fan, as well as for someone who appreciates comedy and drama. Check it out. :-) Sincerely, C. Keith Ray 2005.Sep.19 Mon
Using Cocoa's Reflection APIs for Reading/Writing an SQL Database
CoreData is probably doing something like this already. If you don't like CoreData's use of sqlite3/XML or being limited to the Tiger version of MacOS X, you can probably use these APIs to implement your own object-to-database mapping. If you want to work with a database schema that doesn't map simply to your classes, look elsewhere. Also: I'm just getting to know SQL-based databases, so I may be mis-using SQL/DB terminology or concepts. Writing to the database: 1. Call the method "className" to get the object's class-name and map that to a database table. You probably also want to map object addresses to a unique id in that database table. 2. Calls these methods to find keys of the object and map those to column-names (and possibly foreign keys to other tables): "attributeKeys", "toOneRelationshipKeys", "toManyRelationshipKeys" 3. Get values for keys by calling "valueForKey:" or "dictionaryWithValuesForKeys:". There's also "mutableArrayValueForKey:" for dealing with to-many relationships. 4. Assemble SQL from the classname/tablename, key-names/column-names, and values gotten above, and use that to write to the database. You'll probably need to write multiple rows to multiple tables to persist a complex aggregate object, thus you need to use techniques common to object-serialization to detect cycles and avoid writing an object to the db more than once. One of the PLoP books had a good discussion of serialization. Reading from the database is pretty much the reverse of the above, but getting to the class from a classname/tablename requires calling NSBundle's "classNamed:" method or some other method or function I haven't found in my quick search using AppKiDo while writing this. Once you have the values and key-names, set them with the method "setValue:forKey:" or "setValuesForKeysWithDictionary:". Cocoa has bunches of interesting methods like "classForArchiver" and "replacementObjectForArchiver:" that are probably used behind the scenes for implementations of Distributed Objects, reading/writing NIB files (in various NIB file formats, which recently included XML, I believe), and more recently, Core Data. Maybe someday I'll get more familiar with these. Oh, I haven't actually done this (yet), so don't ask me for help if you get stuck. :-) 2005.Sep.09 FriReally cool, funny book teaching Ruby here. Funner than "Mr. Bunny's Guide to Java" and actually educational. Cutter IT Journal apparently published a study "What Metrics Say About XP" by Michael Mah where five XP projects were compared to five waterfall-style projects inside a medical devices company. The XP projects completed 25-30% sooner and had one fourth the defects of the traditional-style projects. John Roth provides an idea to force programmers to create abstractions (hopefully appropriate for their application's domain). Quote: 2005.Sep.08 Thu
The Simplest and Yet a Very Effective Feature Request tracking tool
One that works well for small, co-located teams is the index card for small features/stories. Particularly nice if you are doing iterative development and you can put the index cards on the wall, partitioning the wall in designated areas: "this iteration's stories" (aka "front burner"), "next iterations stories" ("back burner"), other future stories ("refrigerator"), and not-to-be-done-this-release ("the freezer"). A project might have 100 to 200 stories (or more), but only a dozen or two are on the wall, in the 'active' state, at any time. (Kitchen metaphor names courtesy of Net Objective's Alan Shalloway, see http://www.netobjectives.com/events/specific/pr_nca_2005_08_xbrfasd.htm Slides in pdf form here) Bugs can be considered small features/stories as well, and tracked using index cards and the wall as well. Some teams use red index cards for bugs. If you have so many bugs that you need a database... you have too many bugs. It's really nice to take a bug-report-on-paper, talk to the QA tester about the bug, take it to my computer, fix the bug (writing notes on that paper if I need to), and then take the paper to the QA tester and talk to him about the bug and its fix, leaving it for him to verify. It can then go back on the wall with a mark on it indicating that bug-fix is completed, or go back to me for additional work. For remote employees, I've used a wiki to list stories, track who is working on them and when they're completed. 2005.Aug.27 SatBig Design Up-Front (BDUF) supporters claim that XP doesn't do enough design. See Agile Modeling for the opposing view. That book is naming all the kinds of designing (other than test-driven-design) that XP projects do. We need a new acronym for XP's design practices: not SDUF (Small Design Up-Front), even though that's kinda true, but LoDAtT: Lots of Design All the Time. 2005.Aug.17 WedI've been re-reading the book Are Your Lights On? How to figure out what the problem REALLY is by Donald C. Gause and Gerald M. Weinberg. This is the book that should have become popular instead of "Who Moved My Cheese?". It doesn't talk down to the reader, and it's fairly light-hearted. (Of course, it's not the same subject as the Cheese book, but that's besides the point.) [Problem: a bad book like Cheese was popular, but a good book like this isn't (in comparison). We are the Solution: buy it, and blog about it. Tell all your friends. Get your CEO or CIO or the HR department to buy it in bulk.] Sometimes the problem not considered when coming up with solutions is "whose problem is it?". This book considers that question several times in various real-world situations... such as landlords versus tenants, university president versus professors versus students, competing businesses and government regulators, bureaucrats and travelers. In the area of agile programming practices, and their acceptance or lack of acceptance within an organization, consider who "owns" a problem before trying to solve it. If you are considering automated acceptance tests, what problems are they solving? (And, what problems are they creating?) Are people who feel the pain the most solving their own problem? You can also consider this book as an informal prequel to the more serious book Exploring Requirements: Quality Before Design by Gause and Weinberg. Buy both. 2005.Aug.13 SatEssays by Scott Berkun, author of a project management book, The Art of Project Management, about which Kent Beck said "Reading this was like reading the blueprint for how the best projects are managed at Microsoft. I wish we always put these lessons into action!" "How to learn from your mistakes" quotes: You can only learn from a mistake after you admit you’ve made it. ... The larger your ambitions, the more dependent you will be on your ability to overcome and learn from your mistakes. ... success in learning from mistakes often requires involvement from other people, either for advice, training or simply to keep you honest. ... when you can laugh at your own mistakes you know you’ve accepted it and no longer judge yourself on the basis of one single event. Reaching this kind of perspective is very important in avoiding future mistakes. Humor loosens up your psychology and prevents you from obsessing about the past. It’s easy to make new mistakes by spending too much energy protecting against the previous ones. Why smart people defend bad ideas" quotes: ... one thing I did learn after years of studying advanced logic theory is that proficiency in argument can easily be used to overpower others, even when you are dead wrong. ... The problem with smart people is that they like to be right and sometimes will defend ideas to the death rather than admit they’re wrong. ... if they got away with it when they were young ... they’ve probably built an ego around being right ... Until they come face to face with someone who is tenacious enough to dissect their logic, and resilient enough to endure the thinly veiled intellectual abuse they dish out during debate ... they’re never forced to question their ability to defend bad ideas. Check them out. 2005.Aug.04 ThuSeth Godin blogs: 2005.Aug.02 Tue
Good Stuff on "Blaming Organizations" here:
Beyond Blaming: Congruence in Large Systems Development Projects by Jean McLendon and Gerald M. Weinberg (See also www.satir.org and www.geraldmweinberg.com) It is a fairly long article, here's a few small snips:
What would it take for a new language to impress me?
1. painless interoperability with other languages: C in particular, Objective-C, C++, Python, Java, Ruby, SQL, etc. Objects in this new language should be able to use and/or be proxies for objects in other languages. The language should be usable for shared libraries, plugins, device-drivers, and so on, as well as applications and scripting. 2. support for threads and inter-thread / inter-process communication. Java had "synchronized" but that wasn't enough (and maybe not even the right thing to have). Cocoa's Distributed Objects turn out to be fairly easily used for both inter-thread / inter-process communication, and Cocoa also has support for other ways of synchronous/asynchronous communication, but much of Apple's Cocoa isn't thread-safe. Make it easy to use operating-system threads. Also, make it easy for a programmer to set up a million thread-like objects that don't harm each other and which don't thrash a CPU to death. 3. garbage collection. Look to modern Smalltalk environments for how to do it right. Be able to turn it off for specific objects, etc. 4. work with programmer's weaknesses: many programmers forget to initialize local and member variables... make it easy to init them to a good value, and default to initializing them a zero, null, or default-constructor. Also put in warnings for some other common problems. 5. avoid other language/system weaknesses: learn from common problems areas in Java for example: classpath and class-loaders. 6. consider Objective-C's "message-eating null" -- many people who've never used it expect it to cause problems, but it actually makes programming easier and simpler. Only very rarely do you need to check if a variable is null... and you never get "Null Pointer Exceptions" halting your program. 7. and while you're at it, I'd like to use a debugger that understands objects: let me set breakpoints on ONE specific object: any methods (or any methods that I select) called on that object break into the debugger. Let me add logging of all state-changes to an object, or class of objects, while I'm in the debugger, without writing any code. If I set a break point on a method, let me specify which classes that applies to, if the method is inherited by more than one class. Let me browse all instances of a class (or all classes), and optionally find out where each one was created. Note that I don't talk about syntax, or dynamic-type-checking versus static-type-checking (versus type-inferencing). A correct program is correct in spite of the kind of type-checking that a compiler might enforce. I would want help from the compiler, but not hindrances. I've seen a lot of varieties of syntax. I would want something readable (and I don't consider Lisp and Perl - as usually written - to be readable). Pascal might be considered verbose these days, but it was designed for readability and simplicity (a parser for Pascal would be pretty simple, very simple compared to a C++ parser). Smalltalk is very simple, and pretty readable. Objective-C is "unusual" for those used to C++, but it is powerful, and pretty painless in integrating with other languages. I wonder what a combination of Pascal and Objective-C would look like? 2005.Jul.27 WedFrom a paper by Alistair Cockburn and Laurie Williams: Economics. A recent controlled experiment found only a small development cost for adding the second person. However, the resulting code also had fewer defects. The defect removal savings should more than offsets the development cost increase. This paper sites IBM's finding that defects released to end-users cost an average of $8000 to fix. The lower defect rate more than makes up the slightly higher cost of development. Another quote: we zoomed through QA with hardly a hitch. Everyone, myself included, was amazed that it didn't take weeks to debug, especially given that one of the trees had recently spent SIX WEEKS in QA hell. It was obvious that the pairs had dramatically reduced the defect rate. Other effects of pair programming:
Note also that experts can learn from their non-expert partners: 2005.Jul.07 Thu Quoting Dave Astels on Test-Driven Development (aka Behaviour Driven Development):
Brian Marick has been calling this Example-Driven Development. 2005.Jul.06 WedInside Intuit: How the Makers of Quicken Beat Microsoft and Revolutionized an Entire Industry Notice how the founders got requirements from their potential customers before writing and releasing Quicken. Wonderfalls - The Complete Series "The funniest show you've never seen." Killed by Fox after showing only 4 episodes, the DVD set has the entire first season of 13 episodes. It's what "Joan of Arcadia" might be if that series was a romantic comedy and a lot less self-important. Quoting a review: "What sets it apart from other series is the surreal touch and wicked sense of humor. It's never made clear why Jaye hears toys and bookends talking cryptically to her -- is it God? Aliens? Her own mind?" This DVD set is available only because of a letter-writing campaign organized at http://www.savewonderfalls.com/. Go to that site for links to interviews with the cast, episode guide, scripts (which make good reading), etc. 2005.Jul.02 Sat
Cut Your Car Refueling Costs in Half
According to what I've read here, Brazil lessened its dependency on foreign oil by converting, over the course of the last three decades, to gas-alcohol mixtures. Their "flex-fuel" cars and trucks can run on pure gasoline, pure alcohol or a mixture. Currently alcohol fuel in Brazil, made from local sugar-cane, is half the price of pure gas, and 40% of the vehicles are running on it. Most American cars can run on mixture of up to 10% alcohol without modification. There are perhaps 5 million "flex-fuel" vehicles in the U.S. that can burn a mixture as high as 85 percent ethanol. Unfortunately few gas stations can handle "E85" fuel. Adding ethanol to gas has been called a ploy for farm-subsidies, but if the U.S.A committed to it, we could seriously reduce our fuel prices, reduce pollution, and reduce our dependance on foreign oil. If we also gradually convert to hybrid gas-electric cars that can optionally be plugged in for recharging, we further reduce our dependance on oil. Eventually more electric power-plants would be needed for overnight recharging, but few or no power-plants depend on oil. New plants will be more efficient (and thus less polluting) than old ones, so this path will also lead to eventual reductions in pollution.
"One Best Way" versus "Options"
A book I have talks about preferences for 'one best way' (also called 'process') versus 'options'. 'Process' people want one way to do things, want to be told how to do it that way, and want to be told that it is the 'best' or 'right' way. 'Options' people always want to invent a better way. If they're told 'x process' is the 'best way', they'll try to find a better. Options people are good at inventing processes, but not so good at following them. When talking to 'process' people, if you can establish your credentials as someone who should know the 'best' way, explain how following the process of test-code-refactor insures good design. Explain the rules of good design (modularity, encapsulating behavior, cohesiveness, low levels of coupling, etc.) and give examples of how following the test-code-refactor process produces code that meets those criteria and how design-code-(maybe-test) so often fails to produce code that meets those criteria. If you are talking to options people, you can mention how a whiteboard design session before TDD can let you explore options in the design, and how the rules of good design creates flexible code - allowing more options on how to use the code in the future. To get 'process' people to consider options, repeat this phrase: Repeat this saying often. Establish it as a process to follow to avoid traps and dilemmas. 2005.Jun.27 MonIntroduction One Over recent years, in mailing lists and newsgroups, a conversion about refactoring is repeated many times which goes something like this:
A: "Refactoring is [gold-plating | rewriting | unnecessary ]" and so on... and sometimes...
B: "Of course you'll want to have an automated test-suite to insure your refactorings don't accidentally change the intended behavior. Introduction Two Textbooks and courses try to teach good design, almost never show examples of bad design. The only examples I know of are the excellent books Refactoring by Martin Fowler, Refactoring to Patterns by Joshua Kerievsky and Working Effectively With Legacy Code by Michael Feathers. Code smells (names for various categories of bad design) has a chapter in "Refactoring" but could just as easily have a whole series of books. This essay is an attempt to describe one code smell, and how to correct it. The code smell is known as "Long Method" (or Long Function in a non-object oriented language.) The long method represents a lack of proper encapsulation -- it does too much itself, and doesn't delegate that work to the proper authorities. The irony here is the young coders sometimes think putting everything in one method or in one class is encapsulation. A long method often has varying levels of abstraction within a single block of code. Besides having "too much information" in one place, long methods prevent appropriate code re-use: they encourage cut-and-paste code duplication instead of re-use by calling methods and instantiating classes. Long methods are hard to understand. Hard to debug. And they are very hard to test. Here's an example - a 284-line function from an unnamed open-source project:
In this example, the first block of code after the variable declarations starts with a comment "Remove all carriage returns". Any time you see a block of code within a long method that tells what that code is doing, that's a candidate for an Extract Method refactoring. We extract out that code, and use the comment as the name of the extracted method. In this example, 21 lines of code in this method are now replaced with one line of code. And you can bet that somewhere else in our project, we will also want to do something like this - if not removing carriage returns, then maybe removing some other character. This extracted method is also easy to test. The next comment in the code is "Trim all trailing white space" but unfortunately the code to do that is intermingled with code performing other activities. If the original programmer had been programming by intention, he would have created a method named TrimWhiteSpace, which would have been simple to write and simple to test. In this example, understanding this intermingled code and extracting out the TrimWhiteSpace code is going to be difficult enough that I would postpone that refactoring... getting other cleanup done may allow this refactoring to be easier to do, later. Even if you can't get the code as clean as you would like in one pass, doing small amounts of refactoring every day will help increase your productivity, code reuse, and testability See also:
It's long been accepted that software inevitably degrades until it has to be re-written. Advocates of refactoring and iterative/incremental design/implementation reject that idea. Software doesn't degrade unless acted upon by an outside force (most often, programmers). Here's an example of a new requirement, and two ways to satisfy that requirement. One way creates an unsafe "lump" of bad design. The other way modifies the existing design so that the solution-code for the new requirement continues to meet the criteria for good design.
The new requirement, for Apple MacOS X developers using Metrowerks PowerPlant, is Intel support/Universal Binaries. Specifically, the PowerPlant resource files that are in PowerPC (Motorola byte-order) need to work on Intel (Intel byte-order) as well as PowerPC, preferably without modification. These resources are called Ppob resources, and the are stored in binary form. Apple provided a lump of code that flips the bytes in Ppob resources here. Notice how the function _FlipPPob depends on the layout of almost every PowerPlant view/control class. Notice the big switch statement. Note the tons of duplicated code, such as calls to FlipViewData. One unsafe aspect of this _FlipPPob function is that it attempts to work with every view/control class, but there's a danger in that it doesn't really work with every view/control class. The author of this code may have left some view/control classes out, and of course programmers can (and do) define their own subclasses of PowerPlant view/control classes. Let's re-examine the existing design. Ppob resource reading is invoked by UReanimator. It reads enough to identify a view/control class, and creates an instance of that class via a set of nifty templatized factory objects. By using the factory objects, the UReanimator class does not depend on any concrete view/control classes. To read the PPob resource, UReanimator creates an instance of LDataStream, that it passes into the view/control object, which reads the Ppob data from that stream (typed as LStream, the abstract parent class of LDataStream). Each view/control class knows how to read its own data layout from the stream. While we could modify every view/control class to byte-swap the data it reads from the LDataStream, that would be duplicated code. The place to put the byte-swapping is in LDataStream, LStream, or a byte-swapping subclass of LDataStream or LStream. If we are running on an Intel platform, UReanimator can instantiate the new byte-swapping LStream-derived class (or pass in a parameter to LDataStream) The method that reads an int can be transformed from something like this:
LStream & LStream::operator >> (UInt32 & outNum)
{
ReadBlock(& outNum, sizeof(outNum));
return (*this);
}
to something like this:
LStream & LStream::operator >> (UInt32 & outNum)
{
ReadBlock(& outNum, sizeof(outNum));
if ( mByteSwapping )
{
outNum = ByteSwapUInt32( outNum );
}
return (*this);
}
Instead of a lump of poorly designed code (780 lines worth), we have a change in the UReanimator class (probably a one-line change) and a few changes to a existing LStream class; probably less than 100 lines of new code. The new changes are localized. They are not dependent on all the existing PowerPlant view/control classes. Any view/control class that we didn't plan for will still work. We have modified the code to handle a new requirement, without degrading the design. 2005.May.30 MonQuoting Lisa Crispin's Although our [automated acceptance] tests have found regression bugs, over and over the biggest value comes when we (testers and customers) collaborate with the programmers to create the tests. 9 times out of 10, there is a misunderstood assumption or overlooked scenario. Writing those tests before implementing the code to pass the tests helps flesh out those assumptions and scenarios before coding... saving time and avoiding re-work. The tests codify the requirements much better than non-executable documentation does, simply because it can be quickly executed to show if the product is in compliance, whenever the team needs that assurance. 2005.May.26 ThuSince the Smalltalk compiler is just another set of classes within the Smalltalk environment, you can change it if necessary. David Buck shows the the simple changes he made in VisualWorks Smalltalk to enable programmers to write 45200000000 (45.2 billion) as 45.2b, 3000000 (3 million) as 3m, 60000 as 60k and so on. Check it out. 2005.May.24 TueQuoting Enterprise Systems/Stephen Swoyer:
"Bugs" Versus "Defects" and "Issues"
Johanna Rothman, on her blog, recently wrote "I suggested that my client change his naming of 'bug' to 'defect.'" She got several opposing responses. Interestingly, I think one opposing response may have been from a maker of a bug-databases that uses "bug" in the name of its product. The commenters said things like "bug is just a synonym for defect" and "changing the terminology has no benefit". One response said "what would we call the act of removing the defects? Dedefect?". This reveals the idea that the only way to handle bugs is to remove them after-the-fact. Replacing "debugging" with "defect detection and removal" may be wordier, but it provides a different mindset; it allows thinking about "defect prevention" and different ways to do "defect detection" (such as automated tests and other tools in addition to manual debugging). I almost never hear the phrase "bug prevention" but I've heard "defect prevention" fairly often. And we can use the term "defect injection" to talk about how defects get into the code in the first place. Johanna isn't the first to recommend using the term 'defect'. Her most recent blog entry has comments identifying several sources. Another term that can be used instead of "bug" is "issue", as in an "issue-database" instead of a "bug-database". An issue may be a misunderstanding of the requirements. Usually this gets called an "invalid bug", which can be quite discouraging to whomever raised the issue. An issue is something that still needs some resolution, even if it doesn't identify a code defect. In the case of a misunderstood requirement, the resolution may point to the need for better communication and/or better documentation. If I recall correctly, in one of the four volumes of Quality Software Mangement by Gerald M. Weinberg, Jerry recommended both a defect-database and an issue-database, because one issue could be caused by many defects, and one defect could cause many issues. That implies a database that tracks many-to-many relationships between issues and defects. (There probably isn't a commercial product that does this, though the better bug-databases at least allow linking issue-reports to each other.) Extreme Programming aims at keeping defects (and issues) so low that a database isn't necessary. Instead of creating an issue report, an XP team might create a failing automated test. Such as test is better than a simple database entry because: (1) writing automated tests is a way to flush out understanding of the features. (2) A test that is failing because of code defects should start passing when the code defects are fixed. (If not, then this provides feedback that not all of the defects associated with an issue have been fixed yet.) And (3), being automated, that test can be run many times in the future to detect a recurrence of that issue. 2005.May.23 MonThere's an idea that XP is only useful for frequently-released projects, and not so useful for projects that ship annually or less often. I would say that XP is useful for both. Because XP brings up the quality levels for for those teams who adopt practices like automated acceptance tests, test-driven-development, and pair programming, and drives down the numbers of defects produced, XP projects are able to ship more frequently than once a year. (They don't have to.) They're able to release more often because the members of the team and their users can be more confident that what they ship to the user has useful features and few defects. There's an idea that XP is useful only for projects where the requirements are frequently changing. I assert that our understanding of requirements and of the design is frequently changing even on those projects that seem to have "stable" requirements. All the tools of XP can help a project with stable requirements deliver a superior-quality product. "Stable" waterfall projects often don't "demo" or test their features until the end, at which time they don't have time to accept the changes that the users may want: that's an artificial freezing of the understanding of requirements. "Oh well, those changes will have to go into version 2." Iterative/incremental projects demo and test their features as they are implemented, which allows the users (or user-proxy "project managers", testing staff, and the programmers) to update their understanding of the requirements against the functioning code. I went to Google's open house on May 5 (which happened to be 5/05/2005, but that's probably not significant) and listened to a very interesting set of lectures (and a genuine professional "Engineer/Comedian"). One of the interesting bits is a simple algorithmic infrastructure that Google uses for the index of web-pages, and some other purposes: the "MapReduce" programming model. Google indexes the web using a sequence of 24 MapReduce operations. These operations are specified by a custom high level interpreted programming langauge, and distributed across thousands of rack-mounted dual-processor PCs. Using their fault-tolerant parallel processing infrastructure (implemented in C++). The input data is a few thousand terabytes of data represented as files in Google's custom distributed/fault tolerant file system. The output and intermediate output data are several hundred terabytes. As you might expect, the system is i/o bound -- disk i/o and network i/o. Thus the overhead of an interpreted language for map-reduce operations is not the constraint when doing these big jobs. They have to build their own custom gigabit ethernet switches to handle a thousand (or more) rack-mounted PCs -- commercial ethernet switches top out at 64 PCs and cost too much. Their system has to be fault tolerant, since having at least one PC die (or otherwise go out of commission) each day is not unusual for each of their data-centers. 2005.May.21 SatQuoting The Appreciation Gap by Esther Derby: A recent Gallup Poll report quoted this statistic: “…the number-one reason people leave organizations is that they don't feel appreciated, notes the U.S. Department of Labor.” Read the rest of her article on how to offer appreciations, and how not to screw it up. Don't do a praise sandwich or a cheap gift in place of a sincere verbal appreciation. 2005.May.10 TueSeth Godin asks the question "why haven’t you and your team launched as many Purple Cows as you’d like?" and answers it: "Fear". People would rather do the familiar things, and have an acceptable way of failing than risk blame for failing with something different. (Ironic that "fear" only appears once in the wiki page AnAcceptableWayOfFailing that I just linked to. Go to FindPage and search for pages containing the word 'fear'.) Ricard Semler's Semco does everything that other companies fear: there have no managers and no official hierarchy, employees set their own salaries and hours, there is no "core business". Semler says that sticking to a "core business" artificially limits where they can find profits. (Why do most companies avoid branching out into multiple fields? Fear.) Seth writes books about marketing. He champions creating cheap but thoughtful innovations in products, services, and marketing that customers appreciate. But the interesting thing about his book Free Prize Inside! is that half of the book is teaching you, the reader, how to be a change agent in order to get your marketing ideas accepted within your own company. Get this book to learn how to get your company beyond the fear of the new and unfamiliar. 2005.May.01 Sun
A Big Change for a Sustained Change
Quoting Fast Company's "Change Or Die" by Alan Deutschman :
Check it out, and the blog that referred me to this essay: Creating Passionate Users: Change — or lose you mind. This is why I think that an incremental approach to adopting agile practices is less likely to work: people who make partial changes in their work environment can get the "worst" of the agile and non-agile work experiences instead of seeing improvements; it will not encourage them to go further with adopting new practice. 2005.Apr.29 FriI never blog about where I work, but I'll make an exception today. I'm working at Intuit, on QuickBooks for Macintosh. You can buy the 2005 version at Amazon. I can't say what will go into next year's version, but I assure you, that if you need small-business accounting software on MacOS X, it will be worth the purchase or upgrade price. 2005.Apr.23 SatWe all have various rules in our heads, acquired on our life journey from many sources. Learning new techniques sometimes involves "unlearning" (or modifying) some of those rules. On April 5, 2005, in the XP mailing list, Dale Emery wrote of an example of this. He and Elisabeth Hendrickson were teaching a class on unit testing. He wrote:
To surface what rules are in play here, Dale asked a "why" question thusly: "What concerns do you have about making methods public?"
Having gotten their permission, Dale and Elisabeth demonstrated the refactorings Extract Class and Move Method... creating a new class, and moving those private static methods into the new class, making them public along the way. The original class would contain a local or private member variable of the new class type, and would call those public methods using that new local or member variable. Now, as I understand it, the code being used in the training class didn't have security concerns. And, as it turns out, the private methods were static, so they did not mess with the object-state, and therefore making them public would not make the integrity of the object's state vulnerable to misuse. So the last issue of making these private static methods public was that they would "inflate" the class's interface/responsibilities...
Dale and Elisabeth didn't invalidate the rules these people had about private methods, but added a refinement to them... the idea that private methods can be a "design smell" indicating a class has too many responsibilities. Dale sums up:
Michael Feathers has an article dealing with a similar situation - code that seemed well-designed, but was not testable. Making it testable improved the design: beforeClarity.pdf 2005.Apr.12 TueI used to be a master of C++, even serving as a team's C++ "language lawyer"... As the language has become more esoteric, I have purposefully avoided getting into the rat-hole of meta-programming in favor of "real" programming. Now that I'm back on the Mac doing Cocoa programming, I'm getting more work done with less keyboarding because I can use Objective-C in combination with C++. Objective-C has more run-time power and flexibility than C++. Patrick Logan reminds us how easy it is to integrate Objective-C's first-class objects with Python, Ruby, Java, Smalltalk/Fscript... integration that does not require, for the most part, the massive amounts of code-generation that integrating C++ objects to other systems would require. Smalltalk and Ruby's "blocks" (closures) provide a lot of power in a much more simple manner than C++ metaprogramming provides... besides passing a block around to classes and methods, you can implement new methods on blocks, to provide new control structures. This provides some sample of blocks. Smalltalk, Ruby, Python, and Objective-C have ways for a class to intercept "invalid" method calls and do useful things with them - such as forwarding the call over a network (a network-proxy via a single method). To do network proxies in C++ requires code-generation or extensive amounts of template programming. See these Smalltalk examples for a lot of other interesting things that can be done with this interception capability that would require re-writing the compiler in another language. I have been doing some meta programming in Objective-C this weekend. Unlike in C++, meta-programming is done in the same syntax as regular programming. Starting with the Objective-c proxy example here, I'm creating a class to log calls into an object's methods. This involves decoding the method signatures in order to log the arguments. I will be able to do something like this: someObj = [ [ LoggingProxy alloc ] init: someObj ]; to take an existing object and start logging calls to it -- no recompilation of the sources of someObj's class would be needed. I might even be able to call this code from gdb, so my choice to start logging an object could be made at run-time when debugging. Some parts of Aspect Oriented Programming are doable in Objective-C without using a pre-parser/code-generator, by using the forwarding/proxy and introspection features of the language. Apple's Objective-C++ lets me use straight C, Objective-C objects/syntax, and C++ objects/syntax, and mix them in the same source files. (With some care due to differences in object-allocation and exception-handling.) Objective-C++ lets you Alternative Hard(fast) and Soft(slow) Layers within the same language. Apple made their modifications of gcc available to the maintainers of gcc (and the sources are probably on http://developer.apple.com/darwin/ or opendarwin.org), but the last time I checked, the maintainers of gcc declined to accept those changes and make those modifications available on other platforms. If you want the power of Objective-C++, but you're not using MacOS, ask the gcc maintainers to accept Apple's mods -- or buy a Mac. :-) 2005.Apr.08 FriGerard Meszaros seeks feedback here: http://tap.testautomationpatterns.com:8080/index.html: Much of the material on this site is destined for a book to be published by Pearson Education (Addison Wesley). Feel free to comment on the Book Outline or to volunteer to be a reviewer (whether official or otherwise.) Quoting Using Test Doubles:
Check out the nice diagram on that page, which includes "Eager Mock Object", "Lazy Mock Object", and "Recording Test Stub", as well as the other types of dummy objects mentioned above. 2005.Apr.07 Thu
Introducing Agile to a Legacy Code Project
Brian Marick writes:
There's more good advice there. Check it out. 2005.Apr.02 SatQuoting the Google Gulp Faq: 2005.Mar.30 Wed
Response to 'Toyota, XP and Slack'
Isaac Gouy emailed to me: 2005.Mar.29 Tue The concept of Slack I got from DeMarco's book is that fast responsiveness to unplanned work requires people who do not have their schedule filled to 100% capacity. In Theory Of Constraints, we learn that scheduling extra work for any part of the system that is not the constraint will not improve the flow through the system, and may even slow down the entire system. Thus only one part of the system - the constraint - should be scheduled at 100% capacity [if that can be safely done], and other parts of the system should be idle some of the time in order to synchronize flow with the constraint. In my tour of the Toyota-managed NUMMI auto plant. I noticed that there is very little buffering... parts arrive in shipments as often as 4 times a day and get used up the same day. Hundreds of small groups of people work on the line: each group has 83 seconds to do their part of the job on each car that moves down the line. The members of a team ring the bell/electronic-music-chimes if they need their team leader to help - and those chimes are going off almost continuously [not the same team every time]. But the line hardly ever needs to be stopped, meaning that the help from the team's leader is quick enough and effective enough to fix whatever problem that came up within that 83 seconds almost all the time. I did not see people running or otherwise acting in a hurry at NUMMI. It looks like none of the people I saw were scheduled to fill 100% of their 83 seconds with constant work. (Some of the welding robots maybe, but there were few robots). Eighty-three seconds is a short iteration with very small buffers, but after decades of eliminating waste and improving the process, Toyota can take advantage of such short iterations. See also James Shore on Slack and Scheduling and More on Slack. 2005.Mar.28 Mon
Exploring an Extreme of Refactoring
Kent Beck once wrote of the Three Bears [Pedagogical] Pattern (scroll down to pattern #17): to enable a student to learn about something by exploring its limits. Quoting Kent: I have taught requirements engineering with this technique. I ask the learners to write stories that will define the system—too large in scope to be useful, one too small, and one just right. I taught this technique in India and ended up telling the story of Goldilocks and the Three Bears after lunch. Brian Button decided to explore refactoring by taking the Video Store example from Martin Fowler's book and refactoring it into methods one line long, no private methods, and aggressively removing all duplication, particularly duplication of iteration over containers. His starting point (and Fowler's ending point) is the class named "Customer", containing a list of rentals. It has private methods for calculating rental cost and "frequent renter points", and a large method for printing the customer's statement. Brian's ending point is seven classes: Customer, RentalStatement, RentalCollection, Collector, LineItemPrinter, FrequentPointsTotaller, RentalCostTotaller. If he had been programming in Ruby or Smalltalk instead of C#, he probably could have met his goals with only first two classes. Blocks and iteration methods built into Smalltalk/Ruby collection classes would have eliminated the need to create the other five classes. Brian wrote: 2005.Mar.22 Tue Bruce Eckel writes: 2005.Mar.21 Mon I caught part of Scott Ambler's SDExpo talk on database refactorings, and he had lots of comments about integrating DBA's into the developer team(s) for enabling agility, and described a few ways that apps can accessing databases in a decoupled, flexible manner. He mentioned that another "Y2K" hit the retail industry because UPC numbers are increasing in size. He says that business leaders should recognize that this is a repeat of the Y2K fixed-field-width problem and demand more agile software and database practices from programmers and DBAs. Apparently the fixed-field-width problem is easily avoidable if the apps are written properly. ( See http://www.findarticles.com/p/articles/mi_m0DIS/is_3_5/ai_114716526 ) He asked audience members to raise their hands if they could make a simple change (like renaming a column of a table) and re-deploy their database and associated apps in the same day. Only one guy, in a large room filled with database people, raised his hand (I bet that guy worked at Yahoo, Amazon, or Google.) That guy's DB had terabytes of data and 37 apps depending on it, but he could deploy a change in less than one day. Ambler also asked audience members to raise their hands if their database and associated apps had extensive automated testing. The same guy raised his hand, and maybe one other. Check out Scott Ambler's http://www.agiledata.org/ 2005.Mar.19 Sat
Domain Driven Design Temperature
One of the classes at SDExpo West showed an example of some programmer tests (of Test Driven Development). It was something like this:
void testConvertToCelsius() throws exception
{
TemperatureConverter converter;
assertDoublesEqual( 100.0, converter.convertFahrenheitToCelsius(212.0), 0.001 );
}
void testConvertToFahrenheit() throws exception
{
TemperatureConverter converter;
assertDoublesEqual( 212.0, converter.convertCelsiusToFahrenheit(100.0), 0.001 );
}
That's kind of lame. Eric Evan's advice from Domain Driven Design is that classes that end of "-er" or "-or" should be avoided. Here's a test [in Java] that may better reflect the domain.
void testConvertFahrenheitToCelsius() throws exception
{
Fahrenheit tempF( 212.0 );
Celsius tempC( 100.0 );
Celsius tempFconvertedToC = tempF.asCelsius();
assertDoublesEqual( tempC.value(), tempFconvertedToC.value(), 0.001 );
}
void testConvertCelsiusToFahrenheit() throws exception
{
Celsius tempC( 100.0 );
Fahrenheit tempF( 212.0 );
Fahrenheit tempCconvertedToF = tempC.asFahrenheit();
assertDoublesEqual( tempF.value(), tempCconvertedToF.value(), 0.001 );
}
The trouble with that approach is that Fahrenheit and Celsius are two different types for the same kind of measurement. Maybe these tests (and the design they would force) would be better:
void testConvertToCelsius() throws exception
{
Temperature temp( 212.0, Temperature.FAHRENHEIT );
assertDoublesEqual( 100.0, temp.celsius(), 0.001 );
}
void testConvertToFahrenheit() throws exception
{
Temperature temp( 100.0, Temperature.CELSIUS );
assertDoublesEqual( 212.0, temp.fahrenheit(), 0.001 );
}
Perhaps if NASA and Lockheed Martin had used Domain Driven Design when writing the software for the Mars Climate Orbiter, the 125 Million Dollar probe would not have been lost because NASA used metric units for distance and speed while Lockheed Martin used traditional English units. They didn't have to write conversion code, just class names (or "typedefs" or equivalent if using C or other non-OO programming language) that indicate the units being used. Someone expecting different units would be clued-in by the class or type names. The "agile panel" on the first day of SDExpoWest was talking about useless CASE tools -- how managers buy them, engineers try them out and find they're not helpful, and the tools become shelfware -- and how the money spent on those tools COULD have been spent on something more useful. Jerry Weinberg, in the audience, replied to the panel that we don't have to be victims. Professionals choose their tools as appropriate to the situation at hand and make sure others understand that. He said that no surgeon in the operating room would whine about being given a rusty scalpel because "that was all the hospital would pay for." Robert C. Martin said in his class about "Stemming the Offshore Tide" that a study of 15 projects found that doing the programming and other project work in a "war-room" enabled teams to be twice as productive as those that don't. He said that programmers didn't have to give up offices or cubicles for private spaces, or alone-time for thinking things through, but when working on the project, they should be in same room as the testers, business analysts, and other programmers so that any question about the project could be answered without leaving one's chair -- either by looking at charts and diagrams on the walls of the war-room, or by asking someone close by. Of course, it's not just software developers that corporations try to put into cubicles. Hallmark, the greeting card company, did that with its artistic talent -- until Gordon MacKenzie, the author of Orbiting the Giant Hairball: A Corporate Fool's Guide to Surviving With Grace put them into a more productive environment -- old-fashioned roll-top desks next to drawing boards, good chairs, partitions made from antique doors with stained glass -- which was also CHEAPER than cubicles and standardized office equipment. MacKenzie could do that because he had been at Hallmark long enough to have a good reputation, and he had a corporate sponsor who encourage him to hold the job-title "Creative Paradox". He didn't have several studies showing that a particular environment would help artist be more productive. Quoting How does radical collocation help a team succeed?" by Teasleye et al.: 2005.Mar.13 Sun Dale Emery writes:
Dale wrote a message similar to this essay on the XP mailing list. The answer of "question #2" (what action do I take?) for the person who started the message-thread was "use a bug-base" (or perhaps he was asking "should I use a bug-base?"). In many XP projects, the number of bugs is so small that a bug-base is unnecessary. Any bugs that arise are normally fixed in the same iteration in which they are found, unless the bug can be considered a feature (or story) all by itself, in which case it can be tracked using the same method as tracking stories: index cards or simple software. There is some concern that having a bug-base available may encourage treating bugs as something not to fix during an iteration, with the result that more bugs accumulate and the code-base gets progressively less stable over time. By keeping in mind question 1 ("What results do I want?" Answer: Software that meets the requirements -- that is, doesn't have bugs [bugs are failures to meet requirements.]) and question 3 ("What results am I creating?"), a team can discern whether having a bug-base has "legitimize" leaving bugs unfixed, and if so, adjust their answers to question 2. As Dale wrote in the mailing list: 2005.Mar.10 Thu In many environments over the years, software projects become so heavily burdened by technical debt (overly crufty code) that continuing enhancements become so fraught with danger and difficult to do that progress slows down to a crawl. This is when many programmers try to talk their management into doing a complete re-write. One of the problems with a complete re-write is that while it goes on, there are few (or no) resources to maintain the original application, and the end-result is the "same" as before in terms of functionality -- a lot of money gets spent on rebuilding the existing feature-set, and not much has gone into new features. There have been disasters when companies have attempted grand re-writes, many of them stemming from lost requirements: the existing product does "X" and no one remembers why it does "X". Was "X" a requirement, or was it an accident of history -- maybe even a bug? Either the project reproduces "X", and maybe wastes their time reproducing a bug, or they don't reproduce "X", and then find out from end-users (perhaps disasterously) that it's a requirement. In a project driven by automated customer tests (and programmer tests), requirements are encoded by the tests. Unlike requirements documents, the automated tests tell you if the software under test is living up to its requirements by passing or failing when executed. These tests serve as examples of what the code can do and how to do it. See also Wayne Allen asserting that these "tests" are more about communication and design rather than testing. If one wanted to do a complete rewrite of software project, and one had complete suites of tests, a lot of the guess-work is removed. Keep the tests, rewrite the code under test. When all the tests pass (assuming the tests are complete enough), you're done. Refactoring is also best supported by automated tests. Having this support from tests is also helpful in porting to a new platform (or even a new language). Port the tests as well as the code under test, and having the tests pass gives more than a little reassurance that the code is doing the right thing. Of course, tests rarely cover ALL possible uses and failure-points for a piece of code (and still run in a reasonable time); there's no magic bullet. However, code that is unit-tested is usually code that is more well-designed than untested code, simply because getting a piece of code under test requires de-coupling and other good design practices. This helps prevent a project from ever getting so burdened by technical debt that a complete rewrite becomes necessary. 2005.Mar.07 Mon"Many receive advice, only the wise profit by it." -- a fortune cookie 2005.Mar.05 SatPair programming is NOT two people taking turns programming and reviewing. Consider what activities are done in programming: reading code; writing code; thinking about code and design; refactoring; writing tests; reading tests; running tests; occasionally stepping and investigating in the debugger; talking to someone about code, design, and bugs; waiting for compile/link to finish; running the app; and checking in and checking out source code to/from a repository. All of those are done by BOTH people who are pair programming. Part of pair programming's speed increase (approximately twice as fast as one person solo programming) comes from preventing mistakes (rather than identifying mistakes after they've been coded), having more design and test ideas (coming from different viewpoints and experiences), and fast feedback on those ideas. Quoting "Why Crunch Mode Doesn't Work" by Evan Robinson: 2005.Mar.01 Tue
XP Explained, Second Edition, again (and IXP)
Check out Michele Marchesi's summary 1st edition Values: Communication, Simplicity, Feedback, Courage. 2nd edition Values: Communication, Simplicity, Feedback, Courage, Respect. IXP Values: Communication, Enjoyment, Learning, Simplicity, Quality. 1st edition Principles: Rapid Feedback, Assume Simplicity, Incremental Change, Embracing Change, Quality Work, Teach Learning, Small Initial Investment, Play to Win, Concrete Experiments, Open/honest Communication, Work with people's instincts - not against them, Accepted Responsibility, Local Adaptation, Travel Light, Honest Measurement. 2nd edition Principles: Humanity, Economics, Mutual Benefit, Self-Similarity, Improvement, Diversity, Reflection, Flow, Opportunity, Redundancy, Failure, Quality, Baby Steps, Accepted Responsibility. 1st edition Practices: Planning Game, Short Releases, On Site Customer, Metaphor, Sustainable Pace, Pair Programming, Continuous Testing, Refactoring, Simple Design, Continuous Integration, Collective Code Ownership, Coding Standards. IXP Practices: Readiness Assessment, Continuous Risk Management, Project Chartering, Project Community, Test-Driven Management, Sustainable Pace, Storytelling, Planning Game, Storytesting, Frequent Releases, Small Teams, Continuous Learning, Sitting Together, Iterative Usability, Evolutionary Design, Story Test-Driven Development, Continuous Integration, Collective Ownership, Coding Standard, Refactoring, Domain-Driven Design, Pairing, Retrospectives. 2nd edition Practices: Primary Practices: Stories, Weekly Cycle, Quarterly Cycle, Slack, Sit Together, Whole Team, Informative Workspace, Energized Work, Pair Programming, Incremental Design, Test-First Programming, Ten-Minute Build, Continuous Integration. Corollary Practices: Real Customer Involvement, Incremental Deployment, Negotiated Scope Contract, Pay-Per-Use, Team Continuity, Shrinking Teams, Root-Cause Analysis, Code and Tests, Shared Code, Single Code Base, Daily Deployment. Bill Wake summarizes the key points of this new book, which is a complete rewrite -- different from the first edition in both tone and content. Check it out. J. B. (Joe) Rainsberger on the XP Mailing list described the first edition as teaching on the martial arts level of Shu (learning the rules via practice) and the second edition as Ha (reflecting on the rules and their exceptions), referring to the wiki page Shu Ha Ri. 2005.Feb.27 SunBret Pettichord wrote: 2005.Feb.25 Fri Smalltalk: Planet Smalltalk. Check it out. Agile and Systems Thinking: SystemsThinking.net. I'm reading Rachel Davies via that aggregator, among others. 2005.Feb.22 Tue"One never notices what has been done; one can only see what remains to be done." – Marie Curie, letter (1894). To avoid this problem, make sure to celebrate completed stories and projects. 2005.Feb.16 WedWhy does XP do Release Planning and Iteration Planning using Stories (user-centered mini-use-cases) rather than tasks (technically-centered things to do)? Because it's fairly easy to come up with a mostly-complete list of user-centered stories for a piece of software. You can track their completion, and when all the stories are done, you're done writing the software, even if the estimates for the stories varied wildly from the actuals. On the other hand, at the beginning of a project, it's much more difficult to break down a project into technical tasks correctly, and to come up with a mostly-complete list of tasks. We've all had the experience of discovering lots of tasks during the project that were not anticipated at the beginning. The problem of poor estimates is compounded by our lack of perfect foreknowledge of all the tasks to do. By waiting until a story is scheduled in an Iteration Planning meeting (or afterwards during the iteration itself), to come up with tasks for that story, we enable the Lean [pdf] practice of deferring decisions "until the last responsible moment". The decisions for those tasks will be better, in the light of previous development and the situation as it stands "now", than if all technical decisions were made at the beginning of the project -- when we're most ignorant of what technical choices will work or fail. See Alistair Cockburn's "moving" example of tracking the estimated number of boxes to be packed versus tracking rooms to be emptied. See also Ron Jeffries on Big Visible Charts and Running Tested Features Metric. 2005.Feb.15 Tue
BayXP Wed. Feb. 16 - Tools and Techniques
The next meeting of the BayXP user groups will be Wednesday, Feb 16th, 7:00-9:00 PM at the offices of Agitar Software (1350 Villa, Mountain View). The topic is "Tools and Techniques for Agile Software Development". We are very fortunate to have several dynamic presenters who are recognized leaders in the field of developer tools and software testing.
For those arriving on time there will be a tour of Agitar's Agile development room featuring the original version of the now famous lava lamps and extreme feedback monitor written about in Mike Clark's Pragmatic Project Automation book. Doors open at 6:30 PM. The first presentation will begin at 7:00 PM sharp. Meeting Location: Please contact David Vydra with any questions at david@testdriven.com or 510-333-7579 2005.Feb.08 Tue
Pair Programming with a Robot Dog
http://www.object-arts.com/Conferences/Oopsla/2002/XP-BestFriendReport.htm
If you follow the links to the OOPSLA description of the session, you'll see: 2005.Feb.05 Sat A web-site listing design patterns from many sources. See Full List of Patterns, and List of Authors for two good entry-points. It doesn't seem as open as a wiki, but multiple contributors are allowed. Note also that the license is Creative Commons, and the site hosted ("informally") and moderated by Microsoft. 2005.Feb.04 Fri
Agile Project Management Manifesto
Similar to the Agile Manifesto, a group of ten people have gotten together and worked out a small number of principles for "modern (agile/adaptive) (product/project) management". Check it out here: http://alistair.cockburn.us/crystal/articles/doi/declarationofinterdependence.htm. 2005.Feb.03 Thu... because every human personality has its shortcomings, and so long as we are engaged in observing the imperfections of others we deprive ourselves of the opportunity of learning from them.... The greater our imperfections, the more we are inclined to see the faults of others, while those who have gained deeper insight can see through these faults into their essential nature. -- Tomo Géshé Rimpoché. "In preparing for battle I have always found that plans are useless, but planning is indispensable." -- Dwight D. Eisenhower "Our real problem, then, is not our strength today; it is rather the vital necessity of action today to ensure our strength tomorrow." -- Dwight D. Eisenhower 2005.Jan.29 Sat
Extreme Programming Adoption Stories
Slides from a presentation by Bob Jarvis: http://www.nycagile.org/index_files/res/Bob_Jarvis.pdf [pdf]. Starts with an overview of XP and agile, results and metrics start at slide 29, then discusses Agile project management versus Traditional (plan-driven) project management, lessons learned and so on. Paper by Paul Hodgetts on incremental XP adoption versus wholesale adoption of all practices at once. http://www.agilelogic.com/files/RefactoringTheDevelopmentProcess.pdf [pdf]. (See also Agile Logic publications.) In one wholesale adoption, some developers who had training and understood how to do certain XP practices (test-driven development and refactoring), refused to do them when working independently. They didn't believe those practices were the best way to develop software, but didn't speak out about their objections. In the second wholesale adoption Hodgetts describes, then team did not allow time for training, and thus spent so much time trying to learn how to do the practices and trying to produce software at the same time, that they were unable to do either. In the incremental adoption stories, the teams try to identify the worst problems they are currently facing ("process smells"), and adopt specific practices to fix the root causes of those problems. They use metrics (like bug counts per iteration) and retrospectives or informal group reflection to understand and measure the success of the new practices. Success with some practices encourages the adoption of other practices. 2005.Jan.28 FriIn one of the commentaries by Joss Whedon on the Buffy The Vampire Slayer DVD's, or perhaps in an interview, Joss said that he and some of the cast of Buffy would hang out at his place, reading/performing Shakespeare plays. I dreamed a bit of Shakespeare with some of the Buffy cast in it last night, and decided to try my hand at casting this morning: "Twelfth Night" by William Shakespeare, direction, music and lyrics by Joss Whedon cast: Orsino, Duke of Illyria, played by Marc Blucas Viola, in love with the Duke, played by Sarah Michelle Gellar Sebastian, brother of Viola, played by James Marsters Olivia, a rich countess, played by Amber Benson Antonio, a sea captain, played by Anthony Stewart Head Maria, Olivia's maid, played by Charisma Carpenter Sir Toby Belch, uncle of Olivia, played by Alexis Denisof Sir Andrew Aguecheek, played by Nicholas Brendon Malvolio, steward to Olivia, played by David Boreanaz Feste, a clown; Olivia's servant, played by Seth Green "A Midsummer Night's Dream" by William Shakespeare, direction, music and lyrics by Joss Whedon cast: Theseus, Duke of Athens, played by DB Woodside Hippolyta, Queen of the Amazons; betrothed of Theseus, played by Amber Benson Hermia, in love with Lysander, played by Sarah Michelle Gellar Lysander, in love with Hermia, played by James Marsters Egeus, father of Hermia, played by David Boreanaz Demetrius, in love with Hermia, played by Danny Strong Helena, in love with Demetrius, played by Alyson Hannigan Oberon, King of Fairies, played by Anthony Stewart Head Titania, Queen of Fairies, played by Emma Caulfield Bottom, a weaver, played by Nicholas Brendon Puck, or Robin Goodfellow, played by Eliza Dushku Philosrate, Master of the Revels, played by Armin Shimerman Quince, a carpenter, played by Harry Groener Snug, a joiner, played by Alexis Denisof Flute, a bellows-mender, played by Michelle Trachtenberg Snout, a tinker, played by Adam Busch Starveling, a tailor, played by Marc Blucas unnamed man, plays the Wall, played by Tom Lenk unnamed Fairy (first dialog with Puck), played by Julie Benz Peaseblossom, a fairy, played by Juliet Landau Cobway, a fairy, played by Kristine Sutherland Moth, a fairy, played by Charisma Carpenter Mustardseed, a fairy, played by Seth Green2005.Jan.26 Wed
Notes from reading Four Levers of Corporate Change
The Four Levers of Corporate Change by Peter L. Brill and Richard Worth "First, we examine human nature and how to persuade employees to work for, not against, change. Second, we discuss power, a subject most executives are even more reluctant to talk about than their sex lives. Properly used, power can make change succeed; misapplied, it can destroy a company's entire effort. Third, we explain how to use social processes to initiate change and give it momentum... overcoming pockets of resistance. And fourth, we describe the role of the leader..." "Universal Solvent" exercise: equal numbers of two opposing groups sit around a table. Each takes a turn to ask ONE question to his opposite number, and then record (without reply) the answer. After an hour, "people had gotten a lot of pent-up feelings off their chests and also begun to see problems from the other group's perspective." (page 27) 1. Crisis clearly demonstrated to all employees - short enough time-frame to require a response, long enough time-frame for a response to be possible. 2. Expert clearly demonstrates how their company is deficient compared to others. 3. Exercises got emotions out in the open to motivate change. 4. Employees created their own concrete plans [in cooperation with each other] to solve the problems revealed by #2 and #1 -- note that management-imposed plans would not be sufficient, nor be likely to be adopted. Fundamental Change requires: 1. strong emotions: fear, greed, pride, recognition, accomplishment 2. (someone/something) must destabilize the existing system [Welch / GE] 3. the changed system must be self-reinforcing 4. vision / ideology of the change reinforces the credibility and legitimacy of the leadership First Principle of Power: people who have power usually do not give it up voluntarily. Second: Hierarchies are the natural order of things. Formal hierarchies can be replaced by informal ones. Third: in each organization, there are different types of power: moral (priests), expertise (gurus), coercive (hire and fire) new CEO, established old company, wanted to restructure the company to cross-functional teams focused on market segments. Resistance from "Field Consultants' and the VP in charge of them -- they did not want to become "sales people". CEO spent months trying to persuade that VP, and after failing to, fired him instead of taking charge of the Field Consultants group or putting a flunky in charge, he set up training to 1. strengthen their commitment to the company 2. change their identities from consultants to sales people 3. change the structure of the organization using "Universal Solvent", employees asked and answered questions on 1. how to improve market share 2. what changes are taking place in the market? 3. how should we respond to those changes? 4. what are the strengths of this company? 5. what is the current strategy? 6. how effective is communication between this group and others in the co.? NOTE: the CEO is listening to these answers. Training included simulations of mis-communication and blaming. Training on analysis of the markets involved, what was needed to satisfy those customers. After all this, the CEO presents his vision for the new corporate strategy. The consultants are formed into small groups to discuss how the strategy might be applied to their department... and their identities and why they need to change to sales to function effectively in the new markets. Training session where participants play at using new identities Simulation to emphasize the need for team-work and cooperation and usefulness of cross-functional teams. Teams created to gather data needed for the re-org: lead by sales/consultant "stars", not by ex-VP's managers. This last bit, as well as all the training earlier, established a "caring" relationship between the CEO and the employees, by-passing the managers that might try to get into between to resist and redirect the CEO's desires. 2005.Jan.17 Monthis week, Wednesday January 19. Vandana Shah, a Project Lead at Hewlett-Packard will be presenting experiences using Agile Processes in developing internal software projects of significant complexity.
The meeting socializing starts at 7 PM, presentation starts at 7:30 PM and will be held at the offices of: Electronics For Imaging, Inc. Wolfram Arnold and Keith Ray of EFI will be your hosts. 2005.Jan.16 SunOne point I forgot to make in my previous posting: TDD is faster than test-after and code-n-fix. In Test-Driven Development, testing is part of the design process, it doesn't take much time to write a small test that represents a part of your thinking about a problem. Test-after is slower because the traditional design/code process -- without tests -- takes about the same amount of time as the TDD design/code process, and then the traditional coding time is followed by writing tests that take even more time. Also, test-driven code is less buggy than the usual results the from code-n-fix approach. Since bug-fixing by itself is a lot longer than the TDD process, code-n-fix with no automated tests is actually slower when you take coding-time + bug-fixing-time into account. Unfortunately, there is an attitude in this industry that bugs are inevitable, so not much attention is paid to techniques that reduce the creation of bugs -- automated tests, code-reviews, or pair programming. Those of us interested in TDD are still the early-adopters. This explanation of Test-Driven Development provided insight to some people when I was doing a presentation on the subject. Perhaps it will help someone else out there. Imagine that you're designing/implementing a class or function to solve a problem without TDD. Even though we tend to think of design/coding as one "lump" (or two), it's actually an incremental and iterative process for most problems. You pick an initial data-structure and/or an algorithm, and see how it handles various aspects of the problem - perhaps by thinking it through or running the code though the debugger. You adjust the data-structure(s) or algorithm(s) until all necessary aspects of the problem are solved. In a traditional disciplined coding process, you then write unit tests for the working code. In TDD, you do pretty much exactly the same thing, except that you write tests along the way. Each time you consider an aspect of the problem, you write a test to represent that aspect, and then write just enough code (or modify just enough code) to test that aspect, while keeping previous tests passing. When all necessary aspects of the problem have been solved, you end up with a suite of tests and the working code. In the traditional development style, there's a big psychological barrier against writing tests against code that you just spent an hour or two (or days) getting to work. You made an investment (in code), and now you don't really want your investment to be proven bad, so you don't write a really rigorous suite of tests. This is one reason for the rise of testing departments. From what I've seen over the years, most developers don't write unit tests at all, they rely on the "Quality Assurance" people to do black-box tests; if you're one of those that do write unit tests after coding, good for you! If you don't write automated tests at all, please consider adding TDD to your skill-set. In Test-Driven Development, each test that you write is for code that hasn't been written yet. There's no investment yet to be proven bad. You think "I'll need to handle this aspect of the problem, so let's represent this as a test" -- the tests are documenting the problem-space. Unlike traditional documentation of requirements, the tests are executable. In the TDD, you write a test, watch it fail (because the code for it to pass doesn't exist yet), then write the code to make the test pass, and watch the test pass, (sometimes) refactor to clean up the code, removing duplication and other code-smells, and then watch the test pass again, showing that your refactoring didn't break anything. Test-driving the code that solves the problem, independent of user-interface (graphical, web, or otherwise), encourages you to create objects and functions that reflect the problem-domain, particularly if you are trying to do domain-driven-design. Porting Test-driven code is relatively easy, because running the tests can let you know if the solution-part of the ported code is working right, before getting involved in porting the GUI. Contrast that with the code-n-fix approach of writing the GUI first and (often) mixing the GUI code and the solution-code... this mixture makes understanding the problem/solution domain difficult and the mixed-up code is much less portable.
In a "legacy-code" situation, you quite often no longer have access to any design documentation or requirements documentation (other than a user-manual), so you have to reverse-engineer the problem-space and solution-space out of the code. With TDD, you have tests to describe the problem-space, and the solution-space is the code being tested... the rest of the code is the UI, cleanly separated. In TDD, you don't give up any of the learning you've done about design... you employ a new technique for iterating and testing the design that you're evolving. The hardest part is remembering to keep your (test-code-refactor) steps small: you don't need to solve the whole problem all in one shot. 2005.Jan.13 ThuPeople aren't good at mind-reading (another term for mind-reading is "making stuff up" -- see any comedy of errors for examples). Software is even worse at mind-reading. The worst features in Microsoft Word are those that attempt to do mind-reading... auto-formatting, auto-capitalization, auto-correction, etc. A blogger has finally explained where some of the madness in Word's auto-formatting comes from: attempting to interpret the user hitting the TAB key in various situations as if the user has formed habits from type-writers, which don't have auto-indent. [However, typewriter users don't hit the TAB key in the middle of paragraph in order to indent the whole paragraph...] Two problems with this particular mind-reading is that (1) eventually users learn that a word-processor is not a typewriter [that is, if the word-processor behaves consistently and predictably, which Word, to all external appearances, does not], and (2) most people learning to type TODAY are learning on computers, not typewriters. Trying to sometimes emulate a typewriter in a word-processor is about as useless as sometimes emulating a slide-rule when the application is a spreadsheet: oh, the user just dragged the mouse horizontally to the left here -- instead of selecting text or cells, I'll reduce the value displayed instead. The same blogger also says: here: "People who tend to curse Word have had significant prior experience with some other word processing and/or document producing software. People who don’t have that kind of prior experience tend to find Word’s power and features very helpful." I used Word 1.0 and several succeeding versions, and I curse current versions of Word. Does using Word 1.0 count as "some other word processing... software"? Is someone with no experience of alternative programs really finding Word to be helpful? Perhaps they blame themselves whenever Word does something confusing -- self-blaming is very often the case with inexperienced computer users -- so their evaluation of Word has a built-in bias. Jerry Weinberg has a rule about always looking for three interpretations: what else could users of Word, who have no experience with alternatives, be thinking when they say Word is "powerful"? He also says "I don’t make software for Aunt Tillie." Well, yes, you do. Word's monopoly status in the word-processing market for Mac and Windows means that you're making software for everybody, not just power-users. And that mind-reading about TAB key usage certainly sounds like trying to cater to Aunt Tillie, who learned to type on a typewriter 30 years ago. 2005.Jan.11 TueChristopher Diggins asks "What would a developer expect from a more agile C++"? My answer: the first steps towards agility from C++ would be to move away from the source-file-based compiler/linker setup. Consider that Extreme Programming, the first Refactoring browser, and many of the people involved in the Design Patterns movement all started with Smalltalk programmers. In Smalltalk, the compiler, byte-code-interpreter, the debugger, class browser and editors, and all classes and methods, are all objects that can be manipulated like any other by writing code or using tools provided in the GUI environment. While Java code starts as source files, a Java source file has to parsed only once to create a .class file: after that, when compiling other source files, any references to that class can work with the .class file instead of re-parsing the source. Contrast that to C++ compilers that have to reparse the header files for every source file that #includes them. Sure, there are some optimizations supported by various compilers and IDE. I use #pragma once and precompiled headers when my development system supports them, but the text-file based system, the preprocessor, and the syntax of C++ combine to make it very difficult for anyone to create refactoring tools for C++. Without refactoring tools, C++ will never be as agile as Java or Smalltalk. Consider using Objective-C as a dynamic C-based language instead of C++. It has some reflection capabilities, and its classes are represented as objects at run-time. Objective-C's objects are "completely" polymorphic (unlike non-virtual methods in C++) and the "optional-typing" features of the language allow header files to be almost entirely empty -- speeding compilation. Objective-C is still being enhanced by Apple... try/catch/finally has been added not too long ago. Key-Value Coding/Key-Value Observing are another useful feature in Objective-C/Cocoa. Two big things missing from Objective-C/Cocoa are refactoring tools and garbage-collection. In theory, a conservative garbage collector could be built into the Objective-C run-time, but in practice there's a lot of legacy code inside and outside of Cocoa that probably would need revision to properly work with GC. While Objective-C still has the problem that C++ has with the preprocessor and including header files, the syntax of the language is simple enough that refactoring tools could be implemented, if the people with the right skills are motivated to work on the problem. 2005.Jan.10 MonThe first rule for doctors is "First, do no harm". That also applies to agile methods. The first two rules for agile is "do what works" and "change what doesn't work". Since agile methods are people-centric, agilists understand that people are what makes change work; change should not be imposed on people.
Rajesh's AYE Conference 2004 Trip Report
I've been to two AYE Conferences, almost went last year, and plan to go this year. This can be a life-changing conference. As a result of attending AYE, I had an article published in STQE magazine (now known as "Better Software" magazine), found out about and attended the last PSL, and I got to know many really wonderful people. Unlike many conferences, the sessions are interactive -- not lectures. The "guests" and "hosts" are all participants, and the hosts can learn from the guests as well as the other way around. Rajesh's trip report is in four parts. The first part covers the optional introduction to MBTI, Satir communication model, and Satir change model. Even if you know this stuff, if you haven't attended AYE before, I would recommend going to the optional intro session. When I attended the session, one of the presenters described using the concepts of the Aikido practice of "Center, Enter, Turn" to react to a Blaming attack: take a breath to center yourself, enter the dialog by agreeing with the Blamer that there is a problem to be solved, and verbally turn yourself to be along-side the Blamer as someone to help solve that problem. The second day of Rajesh's trip report covers a session he took on geographically disperse teams, a session on Virginia Satir and her work, and the Agile BOF. When I went to my first AYE conference, agile methods were new, several attendees thought Kent Beck and Ron Jeffries were offensive (and maybe nuts); there were a lot of people asking questions about them, asking XP in particular. Jerry Weinberg invited me and others to dinner to talk about XP. I was able to explain to him and to various people who do rigorous heavy-weight methods that XP isn't an invitation to hack... that the testing and other practices make for a disciplined process. Jerry said XP should be named "a set of practices that people have known to be good for the last 40 years". Jerry was doing iterative software development work on the Mercury space program in 1950's. The third day of Rajesh's trip report, he describes the seesion "Increasing Your Effectiveness as a Change Agent", which seems to either be a new session or one that has evolved a great deal (this is why I need to go back to AYE.) He also attended "Using your Yes/No Medallion", which is one of the Satir tools Jerry describes in More Secrets of Consulting: The Consultant's Tool Kit. The fourth day of Rajesh's trip report, he attended and participated in "Satir System Coaching" (Family Sculpting), and "No Best Practices" by James Bach. 2005.Jan.09 SunInteresting page that I encountered while searching for something else: http://www.third-culture.com/OrgBehavior/MeaningAtWork.htm. It's something like a pattern language: there's a quality (like "Dialogue"), a description section of "when it's lacking" and "when it's thriving", two or three examples, and section of "Action Ideas". It would be interesting if someone turned the "lacking/thriving" parts of this page into an anonymous poll, where employees could rate their companies, and have published cumulative/averaged results published. Quotes from each quality: 2005.Jan.02 Sun
Reviews of C++ Unit Testing Frameworks
Noel Llopis has a survey of CppUnit, Boost.Test, CppUnitLight, NanoCppUnit, Unit++, CxxTest. He has some examples and links to each of those frameworks. Chuck Allison has an article on StickyMinds on XP-style unit testing with his own frameworks (C++ and C versions). William Tanksley described how he and his coworker created CUT, which is on SourceForge/projects/cut/. I use an old version of Michael Feather's CppUnit, with a few changes to avoid warnings from VC++ 6.0 and some additional macros to simplify creating test classes. Creating a simple unit test framework, once you have experience with one, is pretty easy. I would recommend doing it once so that you have the experience; later, if you need a framework when one isn't handy, you can whip one up in an hour or less. This page is something of a clearing-house for unit test frameworks: http://www.xprogramming.com/software.htm. Check it out. Submit your own framework to this page if you want to share it. |
|||||||||||||||||||||||||