Hola, Los Techies


A short note, the guys at the excellent blogging community Los Techies have somehow been fooled into thinking that I have some value on the interwebs and invited me to join, and of course, I accepted.

This blog will still be live for my archived posts, and I may do more with this site. My feedburner feed will roll over so in all likelihood, you won't see this in your reader (if you do email me please).

My new blog home is: http://www.lostechies.com/blogs/scottcreynolds/default.aspx

See you there!

author: Scott C. Reynolds | posted @ Wednesday, September 03, 2008 10:36 PM | Feedback (0)

Speaking at Jax CodeCamp - Weather Permitting!


I will be speaking this Saturday, August 23, at Jacksonville, FL CodeCamp.  I'm doing two presentations, Introduction to Agile Techniques and Measuring Code Quality with NDepend.

Introduction to Agile Techniques will be aimed at audiences looking to find ways to adopt Agile practices at work in a pragmatic way. The focus will be on finding ways to improve your current software development practice with low impact to the organization.

Measuring Code Quality with NDepend will be a demo of the powerful static analysis features of NDepend and an explanation of some key metrics.  Obviously an hour-long talk on NDepend won't come close to doing the product justice, so I will try to hit the high notes and point you to further resources.  I will also be working on a series of blog posts in the future talking more about it.

After the event my slides and other materials will be found on my blog and linked from this post.

There are a bunch of other great speakers at the event, including Sean Chambers, who will be talking about TDD, DDD, and Continuous Integration.  Come on out and get your learn on.

Technorati tags: ,

author: Scott C. Reynolds | posted @ Wednesday, August 20, 2008 9:56 PM | Feedback (2)

Kaizenconf - Calm Down People


Today Scott Bellware released the informational website for the upcoming Open Space in Austin, which is specifically focused on Continuous Improvement in .NET Software Development.

Quickly following the site going live, twitter was raging harder than Tropical Storm Fay about kaizenconf, and why it isn't alt.net.

Now I understand that people assumed that because Scott was doing an Open Space in Austin that it would be "alt.net Austin 2.0", and colloquially people have been referring to it as an alt.net event, but as of June 9, when he posted information in the alt.net mailing list, he was clear that the theme of this conference is Continuous Improvement, not strictly alt.net.

There is absolutely no reason for the alt.net community to feel slighted in any way.  To hear many in the community, the undercurrent of alt.net is, or should be, continuous improvement.  What is happening with kaizenconf is that the question is being posed at a higher level, but alt.net practices and values should find no problem fitting in under the umbrella.

I would ask you to take this as an opportunity to step back from the pure "alt.net" association for a bit and ponder the possibilities that a wider context can bring. I have heard more times than I can count "alt.net is great, but there is an echo chamber effect" and "the values of alt.net are awesome, but people are put off by the name and negativity that has been associated with it".  This is what I hear from people both within and on the outside looking in.  So now that we have an opportunity to talk about our values in a broader scope, why are we so quick to anger?

I am all for having an identity for a community.  It's a focal point from which the community can expand. But if you can't step outside of that identity, or find a way to broaden your context once in a while, then you have to ask yourself which is more important - the community, or that you be identified with it?

Alt.net remains alive and well. Since the beginning of the "movement" the mandate has been to take the larger message and find ways to apply it locally, with your own meetings or gatherings, in your user groups, and so on. I am more than happy to be in alt.net, but I see no reason why we can't flourish in this broader opportunity that the Continuous Improvement conference is presenting.

Technorati tags: ,

author: Scott C. Reynolds | posted @ Tuesday, August 19, 2008 7:14 PM | Feedback (2)

Binding Complex Types to WinForms TreeView with Extension Methods and Generics


So it turns out that the WinForms TreeView control doesn't support binding anything but a Text property to its nodes. This is a pretty lame oversight given what the control is used for (displaying a set of hierarchical data) and we had a need to find a way to bind complex types to the thing. Were this a few months ago we would have had to subclass the control, take in Objects, and do awkward things to make it happen. But now that .net 3.5 is my bff, a quick combination of extension methods and generics will do the trick nicely while still allowing you to use the default TreeView control on the designer surface. (note: you can do extension methods with a hack in .net 2.0 projects and make the same thing happen.)

I sat down and paired this solution with Brian the other day. TDD is your friend once again when writing code, as testing-first allows you to drive out the API and usage before you know explicitly what you want to do. So we knocked out a couple of tests, made them pass, and with just a handful of lines of code, we had a simple solution for binding complex types to a TreeView

The Code - A TreeNode subclass that supports the complex type binding, and 2 extension methods (one for the extended TreeNode, and one for the TreeView itself, to support both TreeViews having nodes, and TreeNodes having nodes). I would like to refactor the names a bit but you get the general idea.

public class ObjectBindableTreeNode<T>:TreeNode
{
    private KeyValuePair<T, string> _boundType;
    private T _boundValue;
 
    public KeyValuePair<T, string> BoundType { get { return _boundType; } set { _boundType = value;
        _boundValue = value.Key;
        Text = value.Value;
    } } 
    public T BoundItem { get { return _boundValue; } }
}
 
public static class TreeViewExtensions
{
    public static void BindComplexDataSource<T>(this TreeView treeView, IDictionary<T, string> dataSource)
    {
        foreach(var item in dataSource)
        {
            var boundNode = new ObjectBindableTreeNode<T> {BoundType = item};
            treeView.Nodes.Add(boundNode);
        }
    }
    public static void BindComplexDataSource<T>(this ObjectBindableTreeNode<T> node, IDictionary<T, string> dataSource)
    {
        foreach (var item in dataSource)
        {
            var boundNode = new ObjectBindableTreeNode<T> { BoundType = item };
            node.Nodes.Add(boundNode);
        }
    }
}

And the tests, which are a little noisy but show the usage (FakeComplexType is just an internal class on the test that has 3 properties)

[Test]
public void bindable_node_should_set_Text_member_when_binding_complex_type_to_a_property()
{
    var testGuid = Guid.NewGuid();
    var complexType = new FakeComplexType() {SomeDisplayValue = "Display", SomeValue = testGuid, FakeNumber = 4};
    var bindableTreeNode = new ObjectBindableTreeNode<FakeComplexType>();
    var dictItem = new KeyValuePair<FakeComplexType, string>(complexType, complexType.SomeDisplayValue);
    bindableTreeNode.BoundType = dictItem;
    bindableTreeNode.Text.ShouldEqual(complexType.SomeDisplayValue);
}
 
[Test]
public void binding_extension_method_on_TreeView_should_create_bindable_nodes()
{
    var testGuid = Guid.NewGuid();
    var complexType = new FakeComplexType() { SomeDisplayValue = "Display", e = testGuid, FakeNumber = 4 };
    var dictionary = new Dictionary<FakeComplexType, string>();
    dictionary.Add(complexType, complexType.SomeDisplayValue);
    var treeView = new TreeView();
    treeView.BindComplexDataSource(dictionary);
    var testNode = treeView.Nodes[0] as ObjectBindableTreeNode<FakeComplexType>;
    testNode.ShouldNotBeNull();
    testNode.Text.ShouldEqual(complexType.SomeDisplayValue);
    testNode.BoundItem.ShouldEqual(complexType);
}
 
[Test]
public void binding_extension_method_on_TreeNode_should_create_bindable_nodes()
{
    var testGuid = Guid.NewGuid();
    var complexType = new FakeComplexType() { SomeDisplayValue = "Display", SomeValue = testGuid, FakeNumber = 4 };
    var dictionary = new Dictionary<FakeComplexType, string>();
    dictionary.Add(complexType, complexType.SomeDisplayValue);
    var treeView = new TreeView();
    treeView.BindComplexDataSource(dictionary);
    var testNode = treeView.Nodes[0] as ObjectBindableTreeNode<FakeComplexType>;
    var dictionary2 = new Dictionary<FakeComplexType, string>();
    dictionary2.Add(new FakeComplexType() {SomeDisplayValue = "subvalue", SomeValue = Guid.NewGuid()},
                            "subvalue");
 
    testNode.BindComplexDataSource(dictionary2);
    var realTestNode = testNode.Nodes[0] as ObjectBindableTreeNode<FakeComplexType>;
    realTestNode.ShouldNotBeNull();
    realTestNode.Text.ShouldEqual("subvalue");
}
Technorati Tags:  
, , ,

author: Scott C. Reynolds | posted @ Friday, August 15, 2008 10:27 AM | Feedback (0)

Ocala/Central Florida Geek Pub Night


Short Notice, but some developers are going to be getting together tomorrow night, Wednesday, August 13, at 7:00pm in downtown Ocala at Tin Cup's Tavern on the square. Topics of discussion will center around building the local dev community, and whatever else you want to talk about. We'd like this to become a regular event to help build the local community.

If you need more information contact me at scott@scottcreynolds.com or via phone at 352-209-0943

Tin Cup's Tavern - Google Maps

Technorati Tags:  

author: Scott C. Reynolds | posted @ Tuesday, August 12, 2008 3:41 PM | Feedback (0)

Tweak of "BDD Naming" AutoHotKey Macro


A while back I read Steven Harman's post about using AutoHotKey on Windows to alleviate the pain of writing underscores into your test names to do BDD-style naming. I am using David Tchepak's version of the macro because I like the way it works and it has the sweet visual tray icon. This macro is a godsend when writing english-sentence-ish names for tests and fixtures, as the underscore is a super pain in the ass, but really helps with readability, and if you are using a tool like SpecUnit.net that parses names on underscores, they're a necessity.

The only friction I've had really using this is that when I am inheriting from a base class in a test fixture, and the macro is running, I have to hit ESC before moving on to the : and the inherited class name. Yeah, it's not a huge deal, but in the spirit of keeping the hands on the home keys as much as possible, I wanted to reduce this little bit of friction. On the plane ride home from CodeStock I had nothing better to do, so I fired it up and made the required script modification

What I needed to have happen was that the test naming mode would toggle off when I typed : (colon) so that I could do test_fixture_name:acts_as_base_fixture_name. Unfortunately, AHK doesn't have a named keyboard input for colon, so I had to do some digging and figure out what it was seeing when I typed :

If you are running a script, you can double-click the icon in the tray and open a window that lets you see the captured keystrokes. Simply type what you are looking to capture and then hit F5 to refresh and see it. On my machine, colon maps to Shift + Special Character 027, which looks like +SC027 in AHK script. With that, I just jumped to the bottom of the script file and added a new key handler that looks like this:

$+SC027:: ;Colon Pressed
SetTestNamingMode(false)
Send, {SHIFTDOWN}{SC027}{SHIFTUP}
return

Then just reload the script, and you will leave test naming mode upon pressing :

Technorati Tags:  
,

author: Scott C. Reynolds | posted @ Monday, August 11, 2008 11:33 PM | Feedback (4)

Moving to the MacBook Pro


ok so I guess I got really used to Windows Live Writer and forgot all the HTML that went into actually properly formatting a blog post. WLW is the ONLY application I have on Windows so far that I haven't found an acceptable replacement for on the mac.

So on Monday my shiny new MacBook Pro came in, and thus began a journey. It was almost like the seven stages of grief, except that I fought for this mac, and I had committed to making the switch. It's been an interesting week.

Funny enough, the announcement came through Twitter about Deep Fried Bytes Episode 5 (Developing for .net on a Mac) at roughly the same time I was announcing my new arrival. Serendipity.

First of all, out of the box some of the experience was very foreign. After using nothing but Windows for so long, I had certain expectations about navigating the OS, installing things, interacting with things, and so on. A couple of IRC/IM conversations later, and I was off to the races. By the end of the first day, the mac felt a lot more natural.

As the week went on I got a lot of tips on applications from some friends, @lazycoder (Scott Koon) in particular was very helpful one night on Twitter. He got me turned on to Adium for IM, Colloquy for IRC, and most importantly, TextMate, which I am using to post this blog entry. I have a feeling I'll be using TextMate for lot of things, but that's another story.

I also got VMWare Fusion and set up a Vista Business VM. As I am still a .net windows developer by day, I need this to get paid. My goal in this however is to have the VM be just a host for Visual Studio, and to do everything else on the Mac. So far so good. Aside from being forced tto install Office 2003 on the VM because I have some Word Interop going on and couldn't build without it, I'm not using the VM for anything but VS2008.

Already in a week I have had my eyes opened to a new way of thinking about the user experience of software in things even as basic as application installation. App installs are basically a joy in OSX, as opposed to my Vista VM which has to be rebooted after each and every multi-gig multi-dialog install experience. The experience of using the applications on the mac is different in many ways too, some of which I like, and some of which I don't, but the important thing to me is that I'm looking at software from another angle, in this system (so far) I'm purely a user, and this perspective change is important for my professional growth.

I am still experiencing some friction, particularly with the keyboard. The layout is fighting a lot of years of muscle memory, and the keyboard shortcuts that I've built up over the years no longer apply. Also I still fumble around the OS trying to figure things out every so often. However, it's only been a week, of part time use, and I feel like I've taken to it well, I have no desire to switch back at all, so I would call that a win.

In the coming n amount of time I hope to use the mac as a jumping off point to really sink my teeth into Ruby, maybe take a stab at some Mac development with Cocoa, and overall continue to improve as a professional software developer by adding new perspectives to my toolbox.


author: Scott C. Reynolds | posted @ Saturday, July 12, 2008 1:46 AM | Feedback (2)

Lean and Agile - Some Thoughts on the Differences


I must start by disclaiming that I am VERY FAR from an expert on Lean. I've read some books. I've seen and been a part of a Lean implementation in a laboratory environment. I am, I hope, actively pursuing an informal but practical education in the discipline, but I am no expert. What follows is my thoughts, my thoughts only, and an open invitation to further conversation on a topic about which I feel passionate. Also I'm not an expert on Agile. I believe strongly that the idea of a named methodology applied rigidly to practice with no flexibility in regard to local constraints is folly.

Maybe it's time to promote one of the agile principles to the forefront: "Continuous attention to technical excellence and good design enhances agility." This statement very clearly has its roots in Lean, but my experience tells me that this is not the rallying cry of the typical agile team. This statement is a good jumping off point, but technical excellence is not the only excellence needed in an organization. However, if this statement were the first statement of the manifesto, we might be having a different conversation right now.

Lean is primarily concerned with two things:  continuous improvement and eliminating waste. In lean these things are actively and aggressively and mindfully pursued. I can't put too fine a point on it.

To be lean is to continuously seek improvements. To understand that there are improvements that can be had tomorrow that you can't see today. To understand that an improvement today may lead you to find waste tomorrow, and that you must eliminate it, and look for more waste. When an organization actively seeks continuous improvement and waste elimination, an individual becomes empowered to be a change agent. Lean, in essence, is a culture of quality, and the ruthless pursuit thereof.

Compare that to the typical implementation of practical agile. Yes, agile may lead to incremental improvements. It may lead to major improvements. It may lead to quality software. But agile teams tend toward a point of stasis where, once the TDD and the CI and the sprints and whatever else is in your agile toolkit are producing a decent velocity, the team becomes comfortable and stops aggressively pursuing improvement in all areas of concern. The methods used to implement agile rarely lead to the sort of relentless pursuit of improvement that is demanded by Lean.

To me, the major differences are that while implementing agile may lead you to quality software development, Lean forces you into a culture of quality. Agile is about interactions and people, and Lean is very much concerned with tools and processes (see Value Stream Mapping, pull systems (Kanban))

The typical team that identifies itself as agile is focused on an extremely local context. Lean is almost always concerned with the larger organization. My thought simply is that Agile can be perfectly happy to stop within the walls of the team room and still be "agile", but Lean will change the organization or die trying. David Laribee has a great post about the idea of the "Agile Shop" that explains what I am trying to articulate here far better than I could, so go read that.

Note that I don't think Agile is worthless. On the contrary, I think the principles of the agile manifesto, applied within a larger context where lean is the primary actor, could make for a very powerful culture of quality. But agile is not lean.

All of the above boils down to a very simple statement for me. If I'm not continuously, relentlessly, aggressively seeking improvement and the elimination of waste, I am not Lean, no matter how Agile I fancy myself.

I encourage you to go learn about Lean, even just get a couple of books on Audible. My typical recommendation is that you do not start with the Lean Software Development books by the Poppendiecks. Of course a software developer will naturally gravitate to these titles because they feel like the context is right, but my feeling is that you must first examine lean, and particularly lean manufacturing, outside of the scope of software in order to really understand it. To that end, I suggest The GoalThe Toyota Way and Lean Thinking as first steps. (I am currently reading Extreme Toyota but am not far enough into it to really give a recommendation.) Then start to think about lean software and read the Poppendieck books with a better understanding of the underlying principles.

Technorati Tags: ,,

author: Scott C. Reynolds | posted @ Friday, June 27, 2008 9:20 PM | Feedback (6)

Go and See for Yourself (Genchi Genbutsu)


A key part of Lean Manufacturing and the Toyota Production System (TPS) is the idea that you should go and see for yourself what is happening on the manufacturing floor. When striving for continuous improvement, or maybe more importantly, true understanding (which must be had before improvements can be made) of the processes and problems on the production floor there is no substitute for being in the place, directly observing the people and machine processes, and when possible, putting your hands into the production line and becoming the person that performs work on the floor.  This is also referred to as the Gemba attitude, or the attitude of being in the place that will feel the direct impact of any decisions made.

The idea is that when you are separated physically from the place of concern any information that comes to you to fuel the decision making process is going to be an abstraction of the real thing at best, and at worst, a totally inaccurate piece of information. Whether you are a marketing person talking to a focus group or a developer taking your marching orders through seven layers of intermediaries separating you from your user, you will end up making the wrong decision. You may get lucky and do the right thing once in a while, but more often than not you will find yourself somewhere down the wrong path.

My current employer is an anatomic pathology laboratory. Our lab, doctors, and medical support personnel are all located in New York, and our IT and development staff are located primarily in Florida. Already we are separated by domain expertise (our developers aren't pathologists or histotechnicians) and we compound that domain expertise gap by putting a thousand miles of geography between us. As professional developers, we all know that the domain expertise gap is hard enough to close even if you can walk into one of your users' offices and talk to him, so when you take that ability away, you have put major impediments in place to creating accurate and useful software for your customers.

To solve this problem, I have spent as much time in the lab as I can get travel budget approval for, and I try to take members of my team with me whenever I can. There is no substitute for seeing your software in use, and for seeing the problems that are either not being solved by your system, or worse, being caused by it. These are things that you absolutely must observe for yourself to understand. A conference call will not convey the information well enough. The bandwidth of face-to-face, in the moment discussions simply cannot always be replaced. Further, when you are physically separated from your customer at all times, you will never hear about certain problems that you could easily solve.

Users are notorious for creating manual workflows to reduce friction in the software they are forced to use. To the developer, it may seem like doing excel or paper processes are high-friction, but we aren't seeing these manual processes from the same perspective as those who created them. Only by walking around, seeing excel spreadsheets or post-it notes in use, and seeking to understand the reason they are being used, and the problem they solve, will you be able to gather enough information to properly create a software solution to this problem.

This past week I took one of my newer developers and a business analyst to the lab. The agenda was "walk around, talk to everyone you see, and ask a question every time you see anything but our software capturing data". From this, in just four days, we have come back with several months worth of work that we just wouldn't have known about, ever.

Another benefit of going to see for yourself is gaining not only an understanding of what your users do, but also an appreciation for the work they do. It's all too easy to become isolated behind the code window and respond to a feature request that on the surface seems stupid or trivial, and dismiss the user as "stupid". But when you go and see for yourself, and see that your users have a mountain of work in front of them that doesn't involve a computer, and are barely able to complete that work in a given day, you can understand better the friction your software and user experience choices causes every day. When your software causes friction, users will find a way not to use it. And when you don't respond to this friction because you feel it is trivial, you lose the trust relationship with your users that you need to operate effectively.

The moral of the story is that you cannot develop software in a vacuum. You must go and see for yourself. And if you can't do that, then you need a proxy to do so. The more layers of abstraction you put between you and the user the less valuable your software will be, so bridge that gap with as many straight paths as possible and seek to understand the production floor and then you will be better positioned to create quality.

Technorati Tags: ,

author: Scott C. Reynolds | posted @ Saturday, June 21, 2008 2:15 PM | Feedback (4)

Deep Fried Bytes Episode 3 Online - Talkin' Twitter from TechEd


So last week I was on my very first podcast, gathered in the INETA lounge at TechEd '08 with the likes of Keith Elder, Glen Gordon, Carey Payette, Alan Stevens, Rob Windsor and Joe Kunk.  We talked about connecting with the community via Twitter (when the fail whale isn't surfacing for air) and about extended tech friends and family.

Check out the podcast at Deep Fried Bytes and see what it's about. There are a couple of episodes ahead of ours, but I'm not on those, so you don't have to listen to them.  Joking.  Listen to them.  And subscribe to the show. It's new but it's going to be a great podcast.

Technorati Tags:

author: Scott C. Reynolds | posted @ Thursday, June 12, 2008 1:51 PM | Feedback (2)

How I Got Started In Software Development


One of my tweeps @mjeaton has asked his sphere of influence to follow on to his post on the same topic, so here we go.

How old were you when you started programming?  The first time I was exposed to programming was around age 10, someone introduced me to BASIC on an Apple IIe in 1987. I don't really remember what we did, as I was interested more in getting back to the game I was playing. This is probably indicative of why I'm not an alpha geek.  All the alpha geeks quit playing games on their C64 in favor of writing opcodes for it.  The first time I got into it for longer than a 5 minute session was when I was 12.

How did you get started in programming?  In 7th grade a couple of friends and I decided we wanted to write a video game, a medieval RPG. We checked out books on BASIC in the library. None of us had a computer. We wrote the game on paper. Couldn't tell you how many lines of code it was, but it was several spiral-bound notebooks worth of code.  Our GOSUBS and GOTOS included page references commented out so we could find shit.

What was your first language?  BASIC. Not sure of the particular flavor anymore, whatever was on the Apple IIe I suppose.

What was the first real program you wrote? I don't even remember the specifics, but I guess it was a program in Turbo Pascal that did graphing functions. I also wrote a Blackjack game in BASIC around the same time, so I can't claim which was first.  These were the first on an actual computer, in 10th grade I took a Pascal class (that I failed) and also finally had pretty much open access to the home computer that my stepmother never trusted me to use prior to this time.  It was a Tandy 1000 or something like that.  Prior to this I wrote several programs on paper.

Incidentally, I gave up programming altogether shortly after that class and didn't come back to it until well after high school.

What languages have you used since you started programming?  If you want to get super trivial about it, BASIC (in several flavors), VB 4, 5, 6, C#, C++, C, Java, Ruby, F#, JavaScript, VBScript, VBA, JScript, Perl, Scheme, the usual suspects in markup and data querying, Pascal, Lua, does DOS Batch language count? I've written some serious enterprise batch files in my time. Probably a few more scripting one-off languages. Even a little assembler.  The only ones I've used significantly are C#, VB, Java, JavaScript, VBScript, Lua, and the markup/data languages.

What was your first professional programming gig?  Well I started my actual paying career in IT as a help desk guy, eventually becoming the network admin and jack of all trades at a large law firm. So the first code I ever got paid to write was VBA macros in Word. At the same job I also hacked together some Perl scripts on the Unix billing system, wrote some VB utilities to manage the helpdesk, and even did some ASP work. I was hooked on getting paid to code after this job.

If you knew then what you know now, would you have started programming?  I think it's at least in part what I was meant to be doing, so yes. I didn't set out to become a programmer. It was a hobby I picked up in middle school that I dropped in high school and only came into as a career accidentally.  It was meant to be.

If there is one thing you learned along the way that you would tell new developers, what would it be?  You are never done learning. And be passionate. If you can't be passionate about this work, it's a tough road to hoe.

What's the most fun  you've ever had...programming? There have been times when I've worked late into the night with other team members on these hell-bound deathmarch projects, and you find a way to make the best of it, and you pull together to write some code over too much Red Bull and cold pizza, and yeah that's not the way to be all the time, but when you can be with a group of peers that are in the same boat and can make the best of it with good music or good jokes or just good support, its good times nonetheless.

 

Technorati Tags: ,

author: Scott C. Reynolds | posted @ Sunday, June 08, 2008 12:34 AM | Feedback (0)

Alt.Net Geek Code Generator


Scott Hanselman talked about this one night down in the lobby of the Marriott in Redmond, and, surprising nobody, actually followed through with it!

Sweetness. Go generate your own.

Technorati Tags: ,,

author: Scott C. Reynolds | posted @ Tuesday, April 22, 2008 7:50 PM | Feedback (0)

Why Alt.Net?


Disclaimer: This post represents my own views of alt.net and is merely an expression of what I would like to see it become. This is not necessarily the view shared by anyone else. I do not speak for this group.

So this alt.net thing has been around for almost a year now (as a named concept anyway), and with the upcoming Seattle event, I've been wondering what my place in this world is, what my contribution can be, and most importantly, what my passion in software is, and how I can work toward it. I want to go to Seattle next month and have something to say, something I believe in, and not just be an observer. The following is a quick dump of my thoughts on the subject.

Thus far my exposure to alt.net has been through various mailing lists, twitter, and blogs by community members. I have virtually met a lot of smart people and great developers through this, but the direction, when it exists, is split. A common goal and purpose seems elusive. Often discussions surrounding alt.net either devolve into the purse fight type of discussion, or filter into a "how can I use/why is [NHibernate, Rhino Mocks, NUnit, Castle] better than [some thing I do RAD|The Microsoft Way]"

Had I my druthers, I would love to see alt.net evolve into a community practicing a variety of (I hesitate to use "best practices" but alternative terms escape me) methodologies with a variety of tools aimed at doing software well, and doing it right, and more importantly, teaching that philosophy, and teaching those practices.

I will forgo the use of labels that may be seen as derisive and divisive, and state my observation from my career that developers fall into two very broad camps: those who at least lurk but maybe participate in "community" activities (blogs, conferences, mailing lists, etc) and those who, for whatever reason, do not. I will call the former Group A, and the latter Group B. Group A may or may not be doing things right. They may or may not be up on the latest tools or methods, but they are out there trying to learn. Group B, contrary to popular may still be out there trying to learn. Those guys just do it primarily through books, magazines, Google, the MSDN library, and their immediate coworkers. Just because a developer hasn't plugged into a community does not mean he doesn't care.

I feel like alt.net, in some part, can be a group that is willing to stand in the gap between Groups A and B and find ways to deliver the right messages to Group B. Developer B may work with one or more Developer A's. We have an opportunity to not just educate A at a code-camp or in a blog post, but help him further educate B, and educate the pointy-haired boss as well. There was talk at one time of alt.net books, and while some thought the idea laughable, the truth is, Group B developers buy books, maybe they have a book budget, and they do what the books say. This is a way to touch non-community-involved developers. Jeremy Miller has made a step in the right direction I believe by publishing an alt.net editorial in MSDN magazine. Lots of Group B types get MSDN magazine. It comes free with MSDN Subscription. Companies that employ Group B types also hire consultants. The consultants can be bringing the message and making sure they are leaving the place better than they found it, not just from a code standpoint, but from a knowledge and understanding standpoint as well. The point is, Group B can be reached if we are willing to find a way and work for it. The question becomes, I guess, is it worth the effort? I say it is. All boats rise with the tide, and if we can force ourselves (not just alt.net mind you, but all Group A types) out of the cabin and into stowage once in a while (it's a funny analogy don't crucify me) then we should see a rise in the industry as a whole.

Alt.net is partially about tools, with good reason. There are good and bad tools out there. There are a lot of great tools that are open source or not "endorsed" by Microsoft that aren't being used simply out of fear. However, talking about tools is not enough. Pushing and IoC container on a developer if he doesn't understand the need it fills and how it fills it is as bad as Microsoft pushing Enterprise Library. I say pushing not because MS made the statement "Thou shalt use EntLib" but because by putting it out their they gave it the de facto endorsement as "the Microsoft Way". How many shops are using EntLib where it is unnecessary, or using it incorrectly, because they were not properly educated on the underlying principles? The tools are a means to an end. But before choosing a means (or an end for that matter), we should be making sure developers are making educated choices.

We need to be teaching people to fish, and moreover, making sure they have the tools to teach the rest of their tribe to fish. There was talk about a "street kit" of sorts aimed (I believe) at this purpose, and I hope to see that come to fruition. But it can't just be about teaching the tools. It has to be about teaching the concepts. To that end, we should be working with each other to make sure everyone is on the same playbook, that we are presenting a unified, educated front when taking the message to the masses. If five different people present TDD you will come away with five different understandings of the why, but a good idea of how to set up a test harness. This is unacceptable. It's an incomplete education, and it leads to misuse and abuse and later abandonment of a good practice. One of the things that David Laribee and others wanted to see happen was the idea of "peer review" for material relating to software development. Sadly, this seems to come up as the exception rather than the rule, at least in the public forums, and as a result we are potentially doing a disservice to the consumers of the information we present in blogs, conferences, and code camps. If we truly want to see software move closer to science and engineering as a discipline then we should be equally disciplined in our research and publishing.

We can't ignore the complexity of a real-world developer's work situation. Jacob Burkhardt said "The essence of tyranny is the denial of complexity." I think that is completely appropriate in this context. I have seen too many conversations about "how do I adopt [x] when my manager/client/stakeholder/team members don't understand it" yield no practical information about how to work with this complexity of environment. Not everyone is out there writing software commercially or as a hired-gun, making their own rules, and working for people that also understand software. Getting buy-in on something as simple as TDD is a non-trivial problem in many IT shops. To that end, I feel like alt.net can do some work to create real, tangible evidence of why the practices we preach are the right practices, why they work better than alternatives, and how to be flexible and still implement them in spirit, or incrementally, to gain the buy-in of those who may be in charge. We need case studies and testimonials that give concrete evidence of how well these practices work. Anecdotal evidence isn't enough.

It's been said that people want to eventually remove the "alt" from alt.net.  I find this to be a powerful goal, but it won't happen, in my estimation, until we are willing to stand in that gap and find a way to bring these practices in a uniform, demonstrable, repeatable way to the masses that exist beyond the glass walls of the alt.net community.

And that's why I'm in the game.

Guys I would love to hear feedback. Am I living in an ideal dream world thinking this goal is achievable? Am I wrong to even think it's that important? I just want to open up some discussions.


author: Scott C. Reynolds | posted @ Monday, March 24, 2008 11:29 PM | Feedback (5)

The Safety Net - TDD IRL FTW Part 2


Bad code snippet example FTL I guess.

Ok so I posted before about TDD helping you by providing a safety net against incomplete testing and developer bias. The very first comment I got was on my code example (which I did say, to be fair, wasn't actually real code). Specifically:

that initial code is smelly in the EXTREME. TDD isn't the problem, nor the solution... proper coding in the FIRST PLACE is missing here.

Ok, fair point. The code is not great. My first instinct was to immediately jump to the defense of the snippet as being an example only, but, after giving it a second thought, I decided to turn that into my next blog post instead!

The fact is, the real live code was smelly. One problem evident in the snippet I used is that basically the same work is being done in the catch as the try, and in fact once we got in there to look at it, it was pretty simple to refactor out that whole bit of try/catch altogether and put the function together a little more cleanly.

Ok but back to the point. I would like to submit a complementary but also contrary opinion to the comment above. More to the point, TDD is a solution that helps you ensure proper coding in the first place, and thereafter.

The Fallacy of "Proper Coding in the First Place"

So we've all been new programmers right? We didn't come out of the womb writing perfectly factored code. We all had to learn. And to learn to write good code, you have to write shitty code. And watch it break. And learn to fix it. And recognize those mistakes before they happen at some point and design in the catches for them. Eventually you graduate to smelly code. Then good code. Then more smelly code sometimes because you've been up for too long. Then some really sweet code that nobody but you can understand. Then, more smelly code. Point is, nobody gets it right on the fly every time.

Sometimes you have incomplete data as to the requirements or the eventual scope of a project or even individual set of functionality. If you believe in various "best-practice" axioms you will probably just solve the problem at hand, you probably won't be super concerned with future-proofing during this iteration. You don't want to suffer Analysis Paralysis, spending all day prematurely abstracting and architecting, because as far as you know right now, You Aren't Gonna Need It. So you write the code that needs written today.

For whatever the reason, the idea that all code can be properly done up front and completely future-proof is a fallacy. Code that is in need of refactoring is the majority of code out there in the world. Bet me it's not.

The Safety Net Is Still Down There

Enter TDD. As I said in the previous post you could have covered the possible scenarios with a handful of tests and had confidence that you covered all the bases. Now, let's say that you realize, or someone tells you, that this code is smelly. Or say you wrote it when you were new, and you have learned, and you want to fix it. Or say you have to fix it because someone else wrote it and it's too smelly and you just can't bear to live with it. One way or the other, you're ready to sit down and refactor it.

So changing code that is in production, or is a dependency to some other code, or that maybe you wrote a while ago and just don't fully remember all the nuances of, can be very scary. And dangerous. However, if you have the unit tests in place that cover the existing code, you are in a much better position, and can approach your refactoring with confidence.

If your tests fully test the various result scenarios of a given function you can change that function and know that if you change something fundamental to the result of the function, your tests may then fail, and you will have instant feedback regarding your refactoring. You can augment your code and your tests to the extent required, and when it's green, you're good. (Simplified explanation, this isn't meant as a full on article on integration and regression testing)

Contrast that to having no tests in place. There may be code all throughout your application that depends on this code. You might make some change that introduces a subtle but real break on one of many dependent pieces. Thinking back to the bias of your own manual testing, and the fallability of human QA people, you may end up creating a pretty severe break in your application that doesn't get caught until sometime down the line when it's in production and not trivial to fix.

TDD Turns Out to Be the Solution After All

In my estimation, at least, TDD solves many problems that occur throughout the lifecycle. If you are test-driving your initial code, you have a better chance of getting it (functionally) correct the first time. Later when you realize that, for whatever reason, either the function or design of the code needs to change, having tests in place can ensure that you don't introduce breaking changes to dependent code. It's a process that repeats over and over throughout the life of any non-trivial application - change happens. It's better to have the safety net when making the changes, whether new functionality or refactoring smelly code, than to not.

No Silver Bullet

Now like I've said before, TDD is not magic. You aren't going to magically never break code or miss a bug or introduce a breaking change again just because you wrote some unit tests. You need to practice writing them to cover more and more scenarios. You need to combine them with other tools that should be in your toolbox as well for you to achieve synergy. Design principles like DRY and SRP, patterns like Dependency Injection, coupled with good testing are practices that will further enhance the robustness and elasticity of your code. And as you start to seriously get into the Test-First mindset as opposed to the Test-Because-I-Have-To one, you will see better design start to be derived in your code as you try to keep your tests from being smelly. Get out there and test people.


author: Scott C. Reynolds | posted @ Wednesday, March 19, 2008 10:37 AM | Feedback (0)

The Safety Net - TDD IRL FTW


To the unintiated, the title is: The Safety Net - Test-Driven Development In Real Life For the Win. Warning - This post contains some of my thoughts about *practical* TDD and the reasons for it. This may not all encompass "dogmatic" TDD practice. To me, TDD is all-important first as a safety net. Before you find TDD soluble enough to understand how it helps you drive design, you have to understand that you're putting it there to save your code from you, your QA group, and most of all, changes.

When I think about TDD, I think about it as an applied methodology and try to determine what real-world scenarios it can improve. Often I hear from people that they don't "get" TDD, that it seems like a lot of extra work, or that they can't seem to find a use for it IRL.  Often, I can see where this kind of thing comes from. Much of what is available out there puts the concepts of TDD in a vacuum and segregates it from the problems it can solve, or doesn't give concrete examples of the benefits of the methodology.

Let's take a step toward changing that. I want to talk about something I had today, and basically recap (and expand upon) a conversation I had with one of my developers regarding unit tests.

The Scenario

A piece of functionality released a few months ago is discovered recently to be buggy. As a matter of fact, recent reports lead us to think that the actual code was never released into the wild at all, as it appears to have completely disappeared. The human testers tested and approved this function (which amounted to an if statement checking a boolean field on a domain entity - pretty simple change). The code was released live. We didn't hear anything for a couple of months, then we start getting a flood of emails telling us that it clearly isn't working.  The testers go back and test, it works for them. The developer goes and looks in the code - the check is there. However, clearly demonstrated reports from users show that the expected functionality is in fact not there.

The Root Problem

We dive into it for a little bit today to find the problem. From a human tester perspective, we are finally able to reproduce the problem by testing some scenarios that they never tested in the first place. From a code perspective, once we removed the blinders that were causing us to look strictly at the line of code implemented, it was easy to spot the problem.

public bool CheckAllowedFunction()
{
    try
   {
        bool securityCriteriaOne = SomeDomainFunctionThatCouldFail();
        bool securityCriteriaTwo = TheAddedCheckFunction();
        if(securityCriteriaOne && securityCriteriaTwo)
            return true;
        else
            return false;
    }
    catch
    {
        bool securityCriteriaOne = SomeOtherDomainFunctionForFailover();
        if(securityCriteriaOne)
            return true;
        else
            return false;
    }
}

Do you see it?  What happened is when the code was first written, securityCriteriaOne was the only check. A year later, when we implement the new request, we add securityCriteriaTwo to satisfy the request, and the check for securityCriteriaTwo was never added to the catch clause (this is a very simplified example, and not entirely representative of the code involved, but it is the basic gist with all the business-sugar stripped out).

Ok, so this is a simple enough mistake. You're flying through, you implement something that you've already decided in your head is one simple line of code (developer bias) and you miss a step. Maybe you hit F5 and run it real quick with your favorite bit of test data in the test system, it works (because your bias led you to test for pass rather than for fail). You build it and ship it to QA. They test. They try to break it, because they hate you. But maybe your QA group isn't strong enough to understand and think through possible breaks. Maybe they have their own set of data they test with, and maybe they got the same bias from the spec that you did and subconsciously tested for pass. Maybe, as in this case, the bug is such that by sheer luck (or Murphy's Law) it looks like it works live long enough that you forget about it. Maybe SomeDomainFunctionThatCouldFail(); is only gonna throw an exception on very rare circumstances, or because of some variance in data (as was the case here). Bottom line, it gets missed.

The Cost

Ignoring any potential business costs for now, because those things are intangible until they happen, let's focus on the cost of this bug to development.

I lost an hour of time when I should have been doing something else. My developer lost an hour of time when he should have been doing something else. The bug was critical enough that he had to interrupt what he was doing for a very important iteration currently. The QA guys lost time testing the current iteration to go back and test (under my direction) a plethora of scenarios. The DBA lost time modifying and creating various data scenarios in the database as I had different scenarios tested. My other developer lost time because well, it was exciting, and we interrupted his work, and it was too interesting not to watch. The VP of IT lost time because he had to stop to get a full understanding of what was going on so he could report up. Pretty much an entire IT department lost an hour plus of time JUST TODAY, not including previous days of trying and *not* being able to identify the bug, just for this simple one line of code.

Clearly, that is unacceptable.

Human QA is Unreliable

Look, I love my testers, and they do a good job. They aren't really my testers though. They're tech support guys that do testing when they aren't answering calls or fixing servers. They aren't trained as testers. They don't have programming experience. They simply don't have all the experience needed to create and execute rigorous test scenarios covering wide ranges of data and usages. They are learning and improving every day, but to expect them to be QA rock stars would be unfair to them and delusional at best.

And I think I have it good. Many of you may not have QA people at all. I've been there more times than I can count. Maybe you test your own code. Maybe nobody tests it (been there too).

Not all of us is lucky enough to have real, dedicated, experienced software QA people testing our apps. And even those of us that do still have bugs. Hello Microsoft? You think they don't have QA people that are probably better coders than me? You're wrong.

Humans are fallable. So are their tests. You need to be in a position of comfort with the robustness of your code before it ever sees another human. You need to know that you caught and handled that Null Reference because John McTestalot might not get it this time. You need the unit-test safety net.

How Does TDD Prevent This Scenario

Well, it's not magic. However, mindful application of test-driven practices will prevent problems like this from happening. In our current iteration we are putting out a lot of functionality. We're releasing to QA multiple times a day, and they are coming back with a lot of bugs. These bugs are, with rare exception, very simple errors and things that got overlooked. Off by one. Bounds checking. Null reference exceptions. Basic stuff.

My guys are writing tests. Only recently have we gotten to the point where we're getting decent testing going, and not putting it off because we "don't have time". The tests are far from perfect, because they are *very* new to TDD, but they're getting there, and they're learning. After reviewing some of the bugs, I told them to learn from these bugs, and start incorporating more thorough tests, and more extensive test scenarios. A bounds error or a null reference should never make it out of your IDE, let alone into the hands of another human. These are things that are easily caught with good unit tests.

And that was the case here. No tests. In my estimation, the original code would, at the very least, have had tests that hit both the try and the catch senario and got its true/false assertions in all 4 places. When the new requirement came in, the tests would then have been augmented with a new bit of code to test securityCriteriaTwo. Then the code would have been written. Then one of the tests wouldn't have passed, the code would have been added to the catch block, and three months later we don't lose 15 man-hours on one if statement.

5 minutes to write a simple test 3 months ago, or 15 man hours to track down the bug today? Which do you think is better?

Why Tests Drive

It's TDD, not DDT (development-driven testing). The tests are first-class citizens. They should come first. No matter how you accomplish this, tests should be driving your new code, not the other way around.

As you get better and better at TDD you will see how it drives not only your code, but your design. But for now, let's focus on the reasons for it driving your code.

The word today is BIAS. Developer bias is your enemy. As I said before, you may look at a requirement, decide in your head it's easy, implement it quickly, then make a test for the implemented function, then maybe make a test for a fail condition so you feel good, then you're done. Bias kicked your code in the nuts the second you typed your first curly brace. You aren't going to go after the fact and write good tests, because you are biased toward the implemented function. You are interested in seeing it work.

Now reverse it.  Let the test drive. You write a test to satisfy the basic criteria of the requirement. You then write exactly what code will make it pass. You then write another test with the intention of making it fail. Then you write exactly what code will make it pass again. Lather, rinse, repeat until you simply cannot think of another way to make it fail. Then you're done. You wrote a bunch more code, sure, but by thinking about the the test over the code, you put out a much more robust function.

Think of it this way: The TEST is the important code. The application code only exists to satisfy the tests. You are trying to implement a full range of solid tests, and then, because you have to, write some code that makes them pass. Putting the test front and center in your consciousness removes the bias toward the application code.

TDD Takes Too Long

I think I've already demonstrated the gains here. 15 man hours of productivity lost today due to less than 1 man hour of time not being spent months ago. Find me a sane manager who will take that trade and I'll help you find a new job because trust me, you don't want to spend another minute with that guy.

But, you say, TDD seems like insurance. It's only useful when it comes up. Sure, this is true in a way, but think of it less like insurance and more like prevention.  You are actively preventing disaster, not trying to just cover yourself in case something happens.

But, you say, it takes a long time, and it's a lot of code to write, and I have more test code in my project than I do real code! Yeah, that'll happen sometimes. That's not necessarily a bad thing. As for the time it takes, well, it takes practice. You don't write perfect tests at first, you don't have good scenario coverage at first, and you feel awkward and unnatural writing tests at first. You gotta practice.

Did you always try/catch/finally when you were cutting your teeth in code? Or did it take many many times of unexpected unhandled exceptions before you started to learn?  When you put in a try/catch/finally today, does it feel like so much extra code? Does it take any measurable time that you feel like you should be applying to other code? Of course not. Unit tests are the next step. They are your next try/catch/finally. Keep at it, knowing the benefits, and they will become a natural, flowing, and quick(er) part of your code-writing.

And they will be your safety net.

Tags:


author: Scott C. Reynolds | posted @ Wednesday, March 19, 2008 12:43 AM | Feedback (2)