Wednesday, July 22, 2009

The Uncle Who Won't Shut Up

Following is a rebroadcast of my comment on Hanselman's blog.

Looking forward to hearing Uncle Bob again. I find him very insightful on coding issues, less so on community issues like how software developers should carry themselves, envision the job, etc. Then there's his politics, which I only mention because it is a large fraction of his tweets (i.e., he mentions it first and puts it in the public sphere). The farther he gets away from technical questions and the closer to sociological theories, he gets less empirical and more loopy. Worse, he also gets more strident, or at least no less so.

I guess he's not the first geek to go a little crackpot when outside his tech strengths. Noam Chomsky, anyone?

Anyway, here's a few questions I'd like someone to ask him. Maybe in part 4?

1. He's pretty big on craftsmanship lately. For the most part, the lesson of history has been, when craftspersons compete with engineering (i.e., industrial processes and capitalist management), the craftspersons get crushed. ("Outcompeted.") The industrial products are more reliable, they scale better, they don't have single-source dependency risks, etc.--and having scaled, their unit cost is cheaper. The "craftsmen" he mythologizes never got around to looking at their products that way; instead, they sat around, pretty happy with themselves, their traditions, and their traditional notions of "quality" and "reliability" until engineers came along and ate their lunch. The engineers innovated, while the "craftsmen" celebrated the past. Given the lessons of history, therefore, why on earth would we want to emulate craftsmen? Or does the "craftsmanship" vision only work for boutique shops, authors, and consultants?

2. He seems pretty ignorant of history with his "professionalism" speeches, too. Strictly speaking, a profession is something that is licensed by the state: doctor, lawyer, even plumber, and (notably) every sort of engineer except software engineer. A profession usually has generations of lore and experience behind it, and a core association (the AMA, the state bars, etc) that maintains "professional standards" and a code of ethics. Thus, in general, an industry has to be a couple generations old AND coalesced around a consensus set of practices before it can even THINK about becoming a profession. (Indeed, that's why the phrase "world's oldest profession" is actually quite a bit funnier, in a dry way, than most people realize today, now that the modern usage of "professional" has stretched to mean "white collar" and/or "not qualifying for amateur status".) I'm pretty sure that if Uncle Bob thought about it, he wouldn't want the government or anybody else telling him who's qualified to write software, or what his ethics should be. Ergo, either he hasn't thought about it, or he doesn't understand the connotations of the words he uses. Either way, he sounds unconvincing.

3. From what I can gather in his tweets and blogs, he's emphatically against not only health care reform, but regulation of the health sector in most any form. I'd love for you, Scott, to ask him how an unregulated insurance market would serve insulin-dependent diabetics, or anyone else who's acutely or chronically dependent on medical treatment. I'd love for you to look him in the eye and ask him what carrier would cover you, and whether you'd ever be able to work for a company smaller than Microsoft and still have coverage. (Of course, maybe you'd rather not entangle your blog and podcasts with that much off-topic drama. It would be quite professional of you, so to speak, to avoid it. But I have several close relatives with diabetes and other health issues, so I'm pretty tired of Uncle Bob's free ride. If he wants to evangelize ideas that would have awful human consequences, I think people should stand up. Your decision is yours, of course.)

Monday, July 13, 2009

INotifyPropertyChanged, C# lambdas, MethodBase.GetCurrentMethod()

I'm on a WPF project at the moment, and Silverlight before that. Both have this notion of INotifyPropertyChanged for bindings, whose only requirement is that you implement
event System.ComponentModel.PropertyChangedEventHandler PropertyChanged
and fire it off whenever any of your properties changes. So far so simple.

The downside is, the PropertyChangedEventArgs payload is not just a typewashed object, it's merely a string of the name of your property, so you see a lot of

public Foo Bar
{
get { return _bar; }
set
{
_bar = value;
OnNotifyPropertyChanged("Bar");
}
}

which works dandy until you rename something or forget to update your copy-and-paste. ReSharper will look in your literals for you, but I'm usually too impatient and sloppy to trust that.

Instead, I've been on a kick to use lambdas and MethodBase.GetCurrentMethod().

First you need a base class like ViewModelBase. Add the following:





   1:   

   2:          protected bool Set<TProperty>(Expression<Func<TViewModelInterface, TProperty>> expression, TProperty newValue)

   3:          {

   4:              TProperty oldValue = _propertyBag.Get(expression);

   5:              string propertyName = expression.GetPropertyName();

   6:              return SetObservable(oldValue, newValue, t => _propertyBag.Set(expression, t), propertyName);

   7:          }

   8:   

   9:          protected bool Set<TProperty>(MethodBase setter, TProperty newValue)

  10:          {

  11:              TProperty oldValue = _propertyBag.Get<TProperty>(setter);

  12:              string propertyName = setter.GetPropertyName();

  13:              return SetObservable(oldValue, newValue, t => _propertyBag.Set(setter, t), propertyName);

  14:          }

  15:   

  16:          private bool SetObservable<T>(T oldValue, T newValue, Action<T> updater, string propertyName)

  17:          {

  18:              bool changed = HasChanged(oldValue, newValue);

  19:              if (changed)

  20:              {

  21:                  updater.Invoke(newValue);

  22:                  // don't fire property change until oldValue is updated

  23:                  OnPropertyChanged(propertyName);

  24:              }

  25:              return changed;

  26:          }

  27:   

  28:          private static bool HasChanged<T>(T oldValue, T newValue)

  29:          {

  30:              bool changed;

  31:              if (ReferenceEquals(null, oldValue))

  32:              {

  33:                  changed = !ReferenceEquals(null, newValue);

  34:              }

  35:              else

  36:              {

  37:                  changed = !oldValue.Equals(newValue);

  38:              }

  39:              return changed;

  40:          }



Somewhere else are your helpful extensions:



   1:   

   2:          public const string GetterPrefix = "get_";

   3:          public const string SetterPrefix = "set_";

   4:          private static readonly int _prefixLength = GetterPrefix.Length;

   5:          

   6:          public static IList<Type> GetInheritedInterfaces(this Type type)

   7:          {

   8:              IList<Type> direct = type.GetInterfaces();

   9:              IList<Type> results = direct;

  10:              foreach (Type implemented in direct)

  11:              {

  12:                  results = results.Union(implemented.GetInheritedInterfaces()).ToList();

  13:              }

  14:              return results;

  15:          }

  16:   

  17:          public static string GetPropertyName<TInstance, TProperty>(this Expression<Func<TInstance, TProperty>> expression)

  18:          {

  19:              return ReflectionHelper.GetProperty(expression).Name;

  20:          }

  21:   

  22:          public static string GetPropertyName(this MethodBase method)

  23:          {

  24:              if (method.Name.StartsWith(GetterPrefix)

  25:                  || method.Name.StartsWith(SetterPrefix))

  26:              {

  27:                  return method.Name.Substring(_prefixLength);

  28:              }

  29:              throw new ArgumentException("Method was neither a setter or a getter.", "method");

  30:          }



where ReflectionHelper is basically lifted wholesale from Fluent NHibernate under BSD. It's not rocket science, though, just some manipulation of C# expression trees to extract the name of a property from a lambda that uses it.

Also, _propertyBag is basically a Dictionary where the strings are the names of the properties. Actually it's a Dictionary to keep some other stuff like original values, dirty bits, etc., but that's another topic.

The implementation of Get is like Set, only simpler.

The net-net of all this is that you can have

interface IMyClass
{
Foo Bar { get; set; }
}

class MyClass
{
public Foo Bar
{
get { return Get(x => x.Bar); }
set { Set(MethodBase.GetCurrentMethod(), value); }
}
}

which is fewer lines, no backing variable (e.g, _bar), and ReSharper-izable. Plus it breaks at compile time until you expose Bar on your interface, so it's as close to idiotproof as I've been able to get so far.


Against software "craftsmanship"

Lots of talk on web lately, esp from Object Mentor types like Uncle Bob and Michael Feathers, about the need for software developers to be more like craftsmen. This is true in small ways, I suppose, but it also seems false in large ones.

The decline of craftsmen, when possible, has usually been industrialization. One can get into frets about alienation of workers from their product, and in fact I usually agree or at least learn from such Marxist critiques. The moral core of those arguments, though, is the degree to which workers are left without meaningful tasks, in the aftermath of initial industrialization. That's a valid point when it applies, but it goes too far when you're just talking about how a software developer who's a dev today, and will be a dev tomorrow, should work.

So I don't think industrialization is evil or without useful lessons in this context. Mostly I think it's an important turning point in technical practices, a sort of coming of age. An inflection point, to use the modern parlance.

Back to software as craft: one of the revolutionaries of the Industrial Revolution was Eli Whitney, he of the interchangeable part. He famously figured out that an army could fight better if its rifles were each made from a finite number of said parts which could be carried into battle, pre-fabricated, rather than requiring a slew of blacksmiths and metallurgists to repair everything on demand. Or, more chronologically, he figured out that this was a better way to make a rifle, then he made a fortune selling rifles of that description to the U.S. Army, because the Army realized he was so, so right.

From interchangeable parts, computer scientists later borrowed the metaphor of subassemblies and, more broadly, decomposition. It's a natural enough idea mathematically, but making it intuitively clear to beginners almost always involves some example from the physical world--especially, the manufactured world.

From decomposition, we get the encapsulated object and the component. From these, we got to the unit test.

Would the craftsman have invented the unit test? To me, the answer is tautologically no. To break a task into subsitutable, commodity parts is, by definition, anti-craft. It is industrial. It is engineering. It's applying arguments (or motivation) of scale; ideas of aggregate, statistical value; perspective at the macro, systemic level; appreciate for complexity, emergent behavior, and the like. By definition, craft appreciates fuzzy essences, "things in themselves," metaphysics rather than physics. Those essences, those things, those human endeavors are valuable, but they are not engineering. I'd argue that the products they produce are not reliable in the way that an industrial product is, and therefore, that software developers should not be craftsmen.

Software needs ideas from the 21st century; the 19th already played out, and the craftsmen lost.

Postscript: Is it me, or is Uncle Bob's software advice, at least as it involves the community of developers (as opposed to pure technical practices like SOLID) getting progressively more hidebound, verging on counterrevolutionary and possibly trending toward stupid?

Monday, June 15, 2009

Odd final sentence in Fowler on UI Architecture

Fowler's overview of UI architectures is pretty much the standard article on the subject. I stumbled on it most recently when MSDN linked there from its Prism docs.

The final sentence has an odd little error, though--odd because this is an important sentence in a widely read article, and the error is quite apparent. The sentence reads, "Mappings will tend to be smaller for Supervising Controller than for Presentation Model as even complex updates will be determined by the Presentation Model and mapped, while a Supervising Controller will manipulate the widgets for complex cases without any mapping involved." (emphasis mine)

Clearly, the highlighted word should have been "simple". The Presentation Model is a stricter mediator of updates than the Supervising Controller is.

I suppose one could make the case that final sentences are so often overwrought, to the point of emptiness, that nobody really reads them anymore. But am I really the first person to be anal enough to notice this? Or is Fowler simply too busy to deal with web errata?

Like many motorists' failures to use turn signals, or the paving of our sidewalks with chewing gum and cigarette butts, overwrought final sentences are yet another symptom of the inexorable collapse of civilization as we know it, or would have known it, had we survived.

Thursday, June 11, 2009

WinMerge in VS2008

James Manning has an MSDN post for VS2005 that still helps when configuring alternative merge and compare tools.

Sunday, May 31, 2009

Silverlight.FX 2.1 navigation

Honestly, I'm torn between loving the declarative emphasis of Silverlight.FX--expressive, implementation-agnostic, terse--and recoiling in horror from how much it depends on string literals for commanding and now addressing/navigation. Also of concern, the MVC stuff follows ASP.MVC's conventions that make type name and file location semantically significant. (E.g., to have a Product controller, you need a type named ProductController in your /Controllers directory. Urgh.) There's a point at which convention-over-configuration strays into anarchy, and I think the ASP.NET pattern has passed it.

Granted, Silverlight is tangled up with xaml and must remain so, if only so it can roundtrip through Blend until something better comes along. This keeps its content quite close to text. And, maybe my love of Resharper has addicted me to static typing to an unhealthy degree, to the point that I want everything reflectable and typed, and I want it yesterday. But am I wrong to be creeped out by the strings? What makes this palatable? Is the theory: "It's acceptably safe to use strings for bindings, so long as they are sufficiently prominent, because their prominence implies that they are unlikely to fail without someone noticing?" (Much as many teams don't unit-test UI's, because the cost of high-fidelity testing is high, and manual testing gives it "enough" coverage.)

I don't get it.

Of course, xaml strings are not always strings. You can do some nifty things with type converters. But then again, type converters are a form of imperative code that's sufficiently subtle to let you THINK you're declarative and whatnot, when in fact you're nearly as entangled with imperative implementations as you ever were. Indeed, ever since a serendipitous typo, I refer to them as "type coverters".

And really, to the extent that they seem "nifty", most things you do with type converters seem so only because there isn't more elegant support in xaml for polymorphism. A richer language would erase (or at least subsume them) in a righteous flash of holy fire.

Monday, May 11, 2009

Uncle Bob, professional opinionator

Uncle Bob is back to his version of talk-radio for the blogosphere. Kernels of truth, whole gallons of certainty.

It's remarkable how many people get into definitional tugs-of-war over "professionalism" without citing the original, technical (if you will) meaning of professional.

Classically, if your vocation doesn't have an professional organization, government licensing requirements, and a code of professional ethics, among other things, you're not a professional. Plumbers are; coders aren't.

In my favorite clarifying example, there's a deep undertone of dry humor to the phrase "oldest profession", probably lost on most people today.

Thus, in the classical sense, anyway, an appeal for professionalism is an appeal to become establishment, institutional, blessed by the powers that be. Culturally (though perhaps not politically) it's conservative. I don't know that Uncle Bob intends this, but if so, it's seems to me this is not what Agile needs.

Craftsmanship, yes; ethics, of course; Marick's Artisanal Retro-Futurism x Team-Scale Anarcho-Syndicalism, very possibly. Speechifying and invective... no thanks.

(Note that I haven't read his actual keynote. Perhaps the speechifying is less in the speech than in the blog.)

Friday, April 10, 2009

Obsolete attribute in .NET

More from the note-to-self category: the [Obsolete] attribute generates compile-time warnings (or errors) but is not enforced by the framework at runtime. This is pretty obvious when you realize its purpose (backwards compatibility that warns but does not break) but spooked one of my coworkers.

Tuesday, March 10, 2009

Bulk unblock in Vista

Vista's UAC suspicion of downloaded code (and other files) manifests itself as a warning on each such file, cropping up when you open them. I usually see this when I download sample code, open the VS .sln, and collapse under the slew of warning windows.

Ideally, my antivirus software would have a setting to remove these values after a successful scan, or at least prompt me. It doesn't.

The fix, like so many fixes, comes from SysInternals. The underlying problem is that the downloaded files have been associated in NTFS's mind with the "main unnamed data stream". Si's streams utility strips off this association, and will do it recursively:

streams -s -d .

The "." for current directory is necessary.

I must have Googled and re-learned this a dozen times.

Wednesday, November 19, 2008

Test pattern

File this under note to self. Say you have a method to test, and inside it looks something like:

public class Foo
{
public bool Bar()
{
return A && B && C && D == "https";
}
}

Meaning, your method has several dimensions of possible inputs, and only one or a handful of acceptable states. Obviously, if the function really is as simple as that, you might not even want a test; static inspection might suffice. But suppose that the evaluation of A, B, and C is a little more complex or expensive, and suppose that there are, say, 3 different acceptable combinations among the full permuation of inputs.

Further suppose that A..D are each enumerable domains. (The actual use case that made me think of this was something like: A is "whether a page requires SSL", B is "the user is authenticated", C is "a certain control is visible", and D is "the protocol on the page request".)

What should the test look like?

The code that began to test-drive the implementation started out like this:

[Test]
public void Bar()
{
Foo foo = new Foo() { A = true, B = true, C = true, D = Uri.Https };
Assert.That(foo.Bar(), Is.True);
// cases 2 and 3 not shown but expect true

// everything else expects false
foo.A = false;
Assert.That(foo.Bar(), Is.False);
// tedious and brittle cut-and-paste looms if not careful...
}

This is the sort of situation you get into with TDD and Simplest Thing That Could Possibly Work. Having plucked the low-hanging fruit in the first few passes, you then need to cover something like "all the other situations". You're tempted to write something like:

[Test]
public void Bar()
{
foreach(bool a in new[] {true, false})
foreach(bool b in new[] {true, false})
foreach(bool c in new[] {true, false})
foreach(string scheme in new[] {Uri.UriSchemeHttp, Uri.UriSchemeHttps, Uri.UriSchemeFile})
{
Foo foo = new Foo() { A = a, B = a, C = a, D = scheme};
Assert.That(foo.Bar(), Is.EqualTo(a && b && c && d == Uri.Https));
// okay, this only covers one of the three acceptance cases; you get the idea, though
}
}

In other words, your verification looks suspiciously like your implementation. Nine times out of ten, that will work. But every so often you discover that you've overlooked some aspect of the problem, and your mirror-image test code didn't identify the discrepancy because it was so similar to the implementation that both had the same bug. (For example: maybe the evaluation of A, B, and C can have side effects that create a subtle a temporal dependency in the order of evaluation, and by duplicating the SUT logic in the test, you never exercise alternative paths.) In general, I feel much safer if the test code takes a different route over the problem space than the SUT does.

You could go table-driven, but then you've got a table to maintain, and how do you know the table is correct? (Read: exhaustive.) Really, you want to codegen the table, which is why I actually like the nested foreach() blocks that iterate over explicit sets in the second version. The loops are clear, terse, and exhaustive. I'd like to keep that portion of the structure while having something that is logically equivalent without being codewise identical.

So, here's the pattern I prefer:

[Test]
public void Bar()
{
// explicitly test each of the small number of outliers
Foo foo = new Foo() { A = true, B = true, C = true, D = Uri.UriSchemeHttp };
Assert.That(foo.Bar(), Is.True);
// repeat for the two other affirmative cases

int trues;
foreach(bool a in new[] {true, false})
foreach(bool b in new[] {true, false})
foreach(bool c in new[] {true, false})
foreach(string scheme in new[] {Uri.UriSchemeHttp, Uri.UriSchemeHttps, Uri.UriSchemeFile})
{
Foo foo = new Foo() { A = a, B = a, C = a, D = scheme};
if(foo.Bar()) trues++;
}
Assert.That(trues, Is.EqualTo(3));
}

Terse? Check. Exhaustive? Check. Sufficiently different? Check. It seems unlikely that, if I refactor this code six weeks from now, I'd make a mental mistake on the implementation that would easily transfer to the test as well.

As they say in math, the proof is by counting.

Sunday, November 16, 2008

Indiscipline kills Agile

That Jim Shore is doing it again. Here's another post I put on his blog.

Agile isn't for everyone. Is that heresy? I turn now, equally heretically, to a sports analogy.

In baseball, there's a belief that an underachieving team can sometimes be improved by bringing in a manager who's not just a different face but a different style. If the previous regime was easygoing with the players, the new one needs to be a disciplinarian, and vice versa. In clubs that are perpetually bad, there's often a perceptible oscillation over time between the two poles.

The interesting thing is, the strategy is thought to work in the short term. Intense managers raise the team's intensity, yielding better results; looser managers increase the team's--I dunno--zen, also improving results. For example: the Tampa Bay Rays got to the World Series this year with a prototypical "player's coach" (Joe Maddon) who replace perhaps THE prototypical disciplinarian, Lou Piniella.

Over time (the conventional wisdom goes), players adjust, cultures change, the results ebb, and eventually the team is ripe for a new revolution.

To return, finally, to software: hidebound developer teams can benefit from Agile. They discover new things about themselves and their business by going iterative and tightening feedback cycles. If they are sufficiently self-aware to capture their discoveries, their engineers can probably engineer an improvement here and there.

However, software developers that can't sustain their own discipline amidst some of Agile's freedoms--i.e., developers who are not especially professionalized or engineerish--are not going to thrive with Agile. Not long term. Indiscipline kills Agile.

Thursday, November 13, 2008

C# primers

So, for reasons bureaucratic related to my master's degree, I've been taking a .NET class. I don't especially recommend taking courses in things you already largely know--especially if long-distance. If you're going to disagree with someone on a philosophical or stylistic point of code, you don't want to do so by email.

Anyway, one of my classmates asked the class,

> What outside reference materials, books, sites, personal advice, etc
> would you recommend for someone with a subpar knowledge of C#/.net in
> regards to this class?

My reply was lengthy enough that it now becomes its own post. It's old hat but I wanted a copy in the archive.

* * *

One of MS's top developer blogs is Scott Guthrie's. He was away over the summer for paternity leave but is gearing up again lately. He writes lots of "how to" pieces and overview pieces about new releases or forthcoming products. He's very senior, so if scottgu's not writing about it, he's probably the boss of someone who is and thus will have a link to it. The comments on his blogs are often useful, too. Extensive archives to search.

Another top blogger is Scott Hanselman, who went to MS about a year ago after being CTO at a firm that got bought. His job now is more or less to evangelize MS developer technologies to the community and advocate for developer issues within MS. His writing is good, and the
comments on his blog entries are usually very smart.

I mostly read the articles but he has a podcast and frequent screencasts, too. Be careful, though: Hanselman is co-author of "Professional ASP.NET in C# and VB", a book that, in my opinion, is a waste of time, money, and trees. It basically repeats what is obvious from the APIs and docs: no useful advice or insight. The code samples are trivial. If I were Hanselman, I'd take my name off the book.

I agree with others' assessments of Jeffrey Richter's main .NET book. Really good but dense. He has a blog but doesn't post much.

Richter is also a contributor to "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries", which is very good at filling a certain niche. The book is almost like a printout of a blog: there are two main authors but several other contributors (such as Richter) whose comments are in sidebars throughout the text. This book won't help you learn how to write your first C# program; it's mostly an explanation of various decisions that
were made by the people who designed the .NET Framework, and recommendations on what "programming in a .NET style" might mean. It also provides anecdotally interesting insight into the amount and styles of usability testing that MS does with its developer tools. (These guys are all very smart, but they realize that they're writing tools for an entire industry of developers, not just the world's elite. When I get worked up about MS doing something stupid, it's nice to be reminded that sometimes MS omits effective solutions not out of raw incompetence but because they want to be all things to all people.) Anyway, if you're someone whose learning/retention is
improved by understanding why* the framework is a certain way, or if you just enjoy deeper understanding, this book can be very helpful.

Joe Duffy is another very smart guy who writes well, and he's written a book for beginners: Professional .NET Framework 2.0. I've only had it for a few weeks but I've liked all the parts I've read. His blog is very technical. He works at MS on parallel programming extensions
to the .NET framework.

If you're going to work professionally on ASP.NET, read Stephen Walther. His "ASP.NET 3.5 Unleased" is my favorite ASP.NET book so far, and his blog has been a steady stream lately of
interesting experiments with the forthcoming ASP MVC framework.

Eric Lippert works on .NET language and developer stuff at MS. Very smart and reflective about how tools and languages relate to good design. He's for professional developers; not recommended fo people who haven't programmed much or who don't plan to. Really wonderful
stuff, though.

Sunday, October 26, 2008

Kanban planning and the reverse event horizon

This was inspired by a thread on Jim Shore's excellent blog. You should probably start there.

Where I work, planned MMFs (as opposed to emergent support items, or dev-initiated work) are pretty chunky: usually several pair-days. Moreover, since we do weekly meetings with the customer to re-assess the queue, and our throughput is much slower than a week (usually 30+ calendar days), items at the bottom can stagnate due to multiple unfavorable re-assessments. Our median (for completed work, whether MMF or no) is much better than our average (for queued MMFs). In practice this means the queue is FIFO/LIELO (First In First Out/Later In Even Later Out).

Indeed, you could make the argument that our queue is not so much a queue as it is a kind of event horizon in reverse. Hey! I'll make that argument.

The event horizon of a black hole is a characteristic distance, such that anything that comes inside its radius gets gravitated in, even radiation, never to be seen again outside the EH. In the case of our planning queue, it's not about the attraction of gravity so much as the repulsive (repellent? there's no upbeat way to say it, and maybe there shouldn't be) force on a task due to other tasks competing their way ahead more effectively. The REH (Reverse Event Horizon) is a number that represents the point in the queue such that, if your task is always that far back, its expected wait time is infinite. The repulsive force is (expected to be) insurmountable.

For us, "constraining" the queue to 7 slots has been anecdotally beneficial, but I suspect the benefit does not especially come from imposing structured flow on development. There's still a considerable amount of chaos in our flow. And, we can't conclude anything more than "anecdotal" benefit because we, erm, have metrics issues that I won't get into here. Indeed, I'm not sure Kanban has changed our development flow at all.

Instead, our benefit comes from not having to plan/estimate/presupport (lose a large amount of our finite attentiveness to) tasks that will never get done, or that will have to be radically re-imagined by the time we are ready to work on them. The information flow has been smoothed, even if the work product turbulence is about where it was before Kanban.

It's not just that the information flow is smoother on a per-task basis, either. I think Kanban has also reduced the baseline difficulty of planning. In particular, I think that once customers began to think of tasks as inventory (and maybe especially as things that both tie up "capital" and lose value over time), they began to give themselves permission to plan less. Or at least, plan fewer: each thing can still get the careful consideration it used to get, but fewer things enter the conversation. I think we all know there's a cost to planning, but Kanban makes its costs more familiar and apparent.

Next post, I'll look at actual numbers to argue that 7 items is a pretty good queue depth for us. Teaser: My guess is that our actual REH is somewhere around 10 or 12. I know that we finish 1-3 queued items per planning iteration.

Saturday, October 11, 2008

The end of history

This blog is hereby rebooted.

POST (power on self test) complete.