How I Set Up My Mac


Some time ago I switched to Mac OS X for my day to day work, using Windows only in a virtual machine for when I absolutely needed to use Visual Studio.

I just got a new 15" MacBook Pro as part of an initiative to roll my entire team over to Mac as our day to day platform (story for another day) and thought I would document my setup for their benefit (and anyone else's).

Step 1 - System Settings

Updates - Do Software Updates until you can't do any more.

Seriously. Just get it out of the way now.

The equivalent of "lock workstation" from Windows

  1. Open System Preferences
  2. Choose "Desktop & Screensaver"
  3. Choose "Screen Saver" at the top
  4. Go to "Hot Corners" and set a corner to activate screen saver
  5. Go back to System Preferences and choose Security
  6. Under "General" check "Require password to wake..."
  7. Check "Disable automatic login"
That done, you roll your mouse to your hot corner, activate the screen saver, and your station is locked. No getting goated!

Trackpad Settings

I like my trackpad a certain way. Tap to click, and tap two fingers to "right-click". These settings are found in System Preferences under Trackpad

My Dock

I don't like to see my dock, so I make it small and auto-hide. I also remove all applications from the dock so that at any given time the only ones there are the ones that are active.

GitHub Setup

If you use Github regularly, then on a new machine you will need to generate your SSH key and set it up in GitHub. Follow the instructions on your account page.

Step 2 - Critical Software

To get up and running immediately, I install the following:

  1. Xcode - Get it from the OS disk. Do it first since gems stuff needs it. Later, sign up for ADC and get the iPhone SDK too. Also MacRuby.
  2. AppCleaner - I like this for doing "uninstalls" and keeping down orphaned file bloat.
  3. Install a launcher. I like Quicksilver
  4. Adium - Chat/IM/IRC (though I use Colloquy for IRC). Let Adium install Growl.
  5. TextExpander - Awesome snippet tool. Add the HTML and CSS bundles from the preferences if you do web work. Add the symbols and accented words bundles too.
  6. TextMate - My editor of choice for most things.
  7. RazorSQL - Manage SQL Server, SQLite, MySql, and many more in this excellent free tool.
  8. Dropbox - for syncing to multiple machines and sharing with people
  9. Mono and MonoDevelop - Doing a lot more of my .net work in MonoDevelop as time goes on. Launching that Windows VM less and less.
  10. Git for OS X
  11. VMWare Fusion - I keep a Vista VM on a separate drive to use when I need it. Running your VMs on an external drive seems faster (slower to start up) for some reason.
I use a lot more in terms of software, but this is the base package needed to get up and running and be productive at work.

Step 3 - Ruby and Rails setup

Setting my rails environment up fresh is a nice couple of minutes of command line goodness. Fire up terminal and do the following:

  1. gem update --system (update the preinstalled stuff)
  2. gem sources -a http://gems.github.com (add github to gem sources)
  3. gem install rspec
  4. gem install rspec-rails
  5. gem install cucumber
  6. gem install webrat
  7. gem install wirble
  8. gem install nokogiri
  9. gem install ZenTest
Next, I edit ~/.irbrc in my favorite editor and make it look like so:
require 'rubygems'
require 'wirble'

Wirble.init
Wirble.colorize

alias q exit

This puts rubygrms and wirble into irb, wirble providing you things like colorizing, history, tab-completion and more. The alias q exit bit is so that q will exit irb for me, giving it a kind of vim-y feel. This is optional.

Step 4 - TextMate Bundles

Being a big TextMate user, I install the following bundles right away:

The easiest way to get these installed is to create the Bundles directory if it doesn't exist:
mkdir -p ~/Library/Application\ Support/Textmate/Bundles/
then go to that directory and start git-cloneing the bundles. Each should have the git-clone command on their readme or wiki. A handy snippet when installing bundles is a little script that will tell TextMate to reload bundles without you having to do it manually:
osascript -e 'tell app "TextMate" to reload bundles'

Other Applications

Other applications that I find useful and install after all of the above:

  • Colloquy - IRC
  • Cyberduck - FTP
  • MarsEdit - Blogging
  • TweetDeck - Twitter
  • Evernote - Note keeping and lists. Syncs with the Evernote on my iPhone. Life is good.
  • Appshelf - App to keep your registrations and serial numbers all in one place. Nicely done.
  • iStat Menus - System Monitoring in the Menu Bar
  • VLC - Plays like...any media format. Seriously.
  • Skype - You know...for skype stuff

Technorati Tags: , , , , ,

author: Scott C. Reynolds | posted @ Tuesday, June 23, 2009 11:22 PM | Feedback (3)

A Couple of Quick Ubuntu Tips


I'm setting up an Ubuntu Jaunty install for a friend and trying to get it nice and usable. I'll be messing more with Linux in the near future I think. Anyway, I ran across a couple of things that really bugged me and that took me a *while* to fix, so I thought I'd share/document for next time.

Side note: I'm damn impressed with how far linux has come since I last gave it a real look. The last time I actually installed linux was pre-corporate-sellout Red Hat almost a decade ago. That experience was...not enjoyable. Ubuntu, thus far, has been every bit as easy to work with as Windows. (Take that for what it's worth)

Font and Options Too Large on Ubuntu Login Screen

First thing I noticed after fresh install was that typing into the login box revealed that the font size was crazy huge. The letters weren't readable at all, and the options menu was barely readable it was so big. Took me a while but I finally found the fix.

Drop into a bash session and type the following:

sudo vi /etc/gdm/gdm.conf

you can replace vi with your editor of choice (gedit provides a notepad-like experience). You are looking for a section that says something like:

[server-Standard]
name=Standard server
command=/usr/X11R6/bin/X -br -audit 0
flexible=true

Edit the command line to include a dpi directive so it becomes:
command=/usr/X11R6/bin/X -br -audit 0 -dpi 96
You will need to reboot to see the changes (or restart GNOME) and the next time you do your login screen fonts should be normal people sized.

The application 'NetworkManager Applet' (/usr/bin/nm-applet) wants access to the default keyring, but it is locked

This one was a pain. I had my friend change her password temporarily so I could do a bunch of setup on her account. This was fine for everything except when Ubuntu wanted to connect to my wireless. It wasn't storing the WEP in the keyring, and it kept prompting about it being locked. Entering the password didn't work at all, and it was pretty much getting annoying.

After searching for a long time and finding nothing, I ran across this thread that provided the answer. Basically, go back to network settings, edit the wireless connection, check "available to all users", and the prompt disappeared.

Random Tips

One thing I found while trying to resolve these issues is that it's much better to include the version of Ubuntu in the search. At first I was trying things like ubuntu login screen font too large and getting very dated results. Changing it to ubuntu jaunty login screen font too large made a world of difference. I guess this may be fairly obvious to most of you, but I'm used to searching for mac os x and not needing to specify leopard.

Also, if you're new to linux or are a keyboarder in general, make GNOME Do the first thing you download and install. It's like Launchy or Quicksilver or [your favorite launcher here] and has been invaluable as I try to find my way around an unfamiliar system. On Ubuntu, you can get GNOME Do directly from the Add/Remove Programs manager (select community-maintained programs).

Those are my Linux tips for today.

Technorati tags: ,

author: Scott C. Reynolds | posted @ Saturday, June 13, 2009 10:48 PM | Feedback (0)

.Net and Ruby/Rails Developers Needed


I apologize to regular readers for this break in my typically mind-blowing content ;)

I am hiring for .net and ruby/rails developers in Ocala, FL. Remote work not an option, collocated team practicing pair programming, BDD, and lean software development.

I am also looking for QA personnel (with a focus on agile testing) and a business analyst.

Great opportunity for the right person(s) to come in and join a busy team.

Send resumes to scott at scottcreynolds dot com.

author: Scott C. Reynolds | posted @ Wednesday, June 10, 2009 5:36 PM | Feedback (0)

Getting up and running on git-svn (5 minute Quickstart)


Git seems to be all the rage these days, and, while I was quite reluctant at first, I am here to tell you that I definitely see what all the fuss is about.

As a bit of intro, these are just a few of the reasons I am loving git:

  • It's FAST. Basically 100% local operation, optimized file compares, it's just plain fast.
  • Cheap local branching. Branches are easy to create, and even easier to merge or throw away.
  • git-stash. The stash is awesome. It's basically a local shelf where you can store some changes temporarily, automatically rolling back the working copy to the last commit, and then reapply what's in the stash at any time. It's not something I use every day, but it's cool.
  • Truly distributed. Star-schema commit structure supported but not required. History is local, operations are local, and with merging being so easy, working disconnected has never been easier.
  • git actually watches your file store. So if you rename/add/modify/delete/move files, it knows, and tracks. No need for IDE integration to solve this headache, and no forgetting to add that new file to svn before breaking the build.

Ok, that's my short list about how I learned to stop worrying and love git. Now I'll talk about something that should be of help to a lot of you out there who, like me, already have your projects under svn and want to get more comfortable with git before switching your whole organization to it en masse.

The good news is during your learning/transition time, you can keep your team on svn and use git with the git-svn bridge. Git-svn gives you local git operations with the ability to interact with the master svn repository, merging commit history for you and being almost completely transparent to the rest of the team still using svn.

Without further ado, I present the getting up and running guide to git-svn.

First, clone your svn repo locally (this is the same as svn checkout) with the command: git svn clone -s http://repourl/trunk. This gives you a local git repo with a master branch that has the svn trunk in it. The -s param is telling git that the standard trunk/branches/tags convention is followed.

Yeah, that's it for setup. Couldn't be easier. May take some time so sit back and relax, but it's still WAY faster than a fresh checkout with Tortoise, I guarantee.

Okay, now that we are set up, on to day to day operations. You do work. You commit locally with git commit -m "commit message". You add new files to git with git add [file] or to add all git add . (period). You do this as often as you like. One of the nicer things about git is that it supports a tight iterative workflow by allowing you these local "micro-commits" without the hassle of integrating each commit.

When you're ready to get latest from svn you do git svn fetch which will get the current trunk from the server, and then git svn rebase to merge your branch and the latest. You can also do a git merge but I have read that it can cause history problems, and that git svn rebase is the way to go. When you are ready to push your local changes to the central svn repo, you hit git svn dcommit and you're done.

Recapping, it's:

  1. create local git repo: git svn clone -s http://svnrepo
  2. get latest from svn: git svn fetch then git svn rebase
  3. make local changes: git add and git commit -m "message"
  4. push to svn: git svn dcommit
repeating steps 2-4 as necessary.

That's it. Easy as pie.

Many thanks to the community, and especially Aaron Jensen, the .net world's chief git evangelist, for all the help they've given me with git.

For more great git resources, check out GitCasts and Gitready, as well as Aaron's blog post linked above and the links contained therein.

author: Scott C. Reynolds | posted @ Tuesday, May 05, 2009 9:22 PM | Feedback (1)

Updated to SubText 2.1.1


Updated the blog to SubText 2.1.1 tonight. Couldn't have gone better really.

Make sure you back up your existing blog directory, then just copy the contents of the zip file over to your server. Don't forget to diff/merge (or just re-edit) your web.config, DTP.aspx, and any skin changes you made. You do need to copy the new skins, because your old one will not work.

The only weird thing is that once you make the upgrade, you go to your blog and log in to the admin thing. If you just go to the site you get this error page that says "no message available" and then has a link if you are the admin to continue along to the upgrade process. Functional, but a little concerning at first before you read the whole page.

Once again, hat tip to my boy Steven Harman, well-shodden supporter of third-world children, and the rest of the SubText team. Aside from still never getting my contact form to work, I've been happy with SubText for several years now.

Technorati Tags:

author: Scott C. Reynolds | posted @ Tuesday, April 28, 2009 11:14 PM | Feedback (0)

Pro Tip: Don't co-opt .net conventions for your own purposes


Right.

So it turns out that the visual studio/.net convention of assembly.extension.config for config files is NOT to be used for your own devices outside of visual studio.

Example:

Today I made an app called whatever.client.exe. It needed to read an xml file for some config, but I didn't want to use Visual Studio to generate that config, and I didn't want the Properties.Settings.Default stuff, for reasons beyond the scope of this post I just wanted to load the xml config file and parse it myself.

Easiest way to do this I thought was name it whatever.client.exe.config and load it by looking at Application.ExecutablePath and appending a ".config".

No dice. Dropping a file with that name in the executing directory of the app caused the app to fail to launch with the message "...failed to start because its side by side configuration is incorrect". Ok then. Even if you just create an xml named with that convention in the application directory, and don't involve visual studio at all, it still dies.

The fix is just name it something else of course, and everything is fine. Learn something new every day I guess.

Edit

Ok so Tomas Restrepo was kind enough to point out that this is a OS convention that is just being used by .net, so it's not .net app-specific. See Here for further information.

Technorati Tags: ,

author: Scott C. Reynolds | posted @ Thursday, April 23, 2009 11:11 PM | Feedback (0)

VMWare Fusion Shared Folders and Visual Studio Development


So today I had a bit of an adventure that I figured I would document for those of you that may run into this same thing and get just as frustrated as I was for many hours trying to make this work.

I do my work on a MacBook Pro these days. My first setup was to do my .net work in a Vista VM using VMWare Fusion. I created a vmware disk to store my code, installed TortoiseSVN, and worked normally as if I were on a regular windows box. It was a nice little self-contained world.

As my usage of other tools grew, I ran into problems with this setup. Namely:

  • Tortoise is aptly named, speedwise. Especially on a VM. But also just on regular windows.
  • My files were locked away in my VM unusable by me (in an easy way) natively on the Mac OSX host. This became an issue as I started to work more and more in alternative tools, like MonoDevelop and TextMate.
  • My files were locked away in my VM unable to be explicitly backed up by TimeMachine. Less of an issue because they're in a central source repo, but still an issue.
  • I wanted to use Git more and git-svn on windows is...slow. Also cygwin and I are not buddies yet. Plus I have a nice Terminal setup.
  • The VMdisk was big, unwieldy, not all that portable, and not all that speedy anyway.

So what I decided to do was set up a VMWare shared folder from my ~/code folder on Mac OSX, exposing it to the guest OS (Vista) as a mapped drive (z: by default). Then I cloned the svn repo with git svn to this folder, checked out a local branch, flipped to my VM, opened the project in Visual Studio, and was prompted with partial trust errors ("Project Location Not Trusted"). At first it seems like ignoring these errors will work, until you go to run some tests, and n number of tools (RhinoMocks, NUnit, SpecUnit, and so on) throw the error that the assembly does not allow partially trusted callers.

Long story short, the solution is to use caspol.exe to set the share to full trust. The documentation on this tool is terse at best, and cobbling together several blog posts (none of which got it right...) I found the command-line magic that made things work.

  1. Disable UAC (may not be completely necessary, but UAC sucks so do it anyway)
  2. Open a Visual Studio 2008 Command Prompt as Administrator (right-click and run as administrator) and run the following:
  3. caspol -m -ag 1.5 -url file://z:/* FullTrust
Breaking that command down a bit, you may have to substitute a couple of params. The -ag 1.5 may be different on your machine. You need to add the share (from mac osx anyway) into the "Internet_Zone" because something to do with the share path starting with a . makes Vista assume it's in the Internet and not Intranet. To find the group number for your Internet_Zone run the command caspol -m -listgroups and look for the one that says "Zone: Trusted-Internet" (or something similar, I make no claims to Vista operating sanely across all installs). Mine was 1.5.

The second bit you may need to change is the actual share location. Mine mapped to z:/ by default, but you'll want to check that yourself.

If all goes well you should get a message about "Added union code group with -url membership condition..." and a "success" status. All that out of the way, I reloaded Visual Studio from the share, ran tests, and they failed, but for the right reasons ;)

Technorati tags:

author: Scott C. Reynolds | posted @ Tuesday, March 31, 2009 12:55 AM | Feedback (6)

Comparing Jon Stewart/Jim Cramer to Alt.Net/Microsoft


This is just a bit of a sidenote to everything else, but I couldn't help but watch the Daily Show interview of Jim Cramer and draw a bit of a conclusion to Alt.Net and Microsoft.

In the interview, Stewart takes Cramer to task over what he feels are practices in business "entertainment" and reporting that are severely lacking in integrity and directly negatively impacting the American people. Some people say he was being "mean". I say he was standing up for something that is important, and applaud him from having the balls to do it on national TV.

In some ways it's a shame that Cramer took the brunt of it, because he is only one face on the problem, but it is what it is, and time will tell if CNBC and other parties respond to the very public beating. My bet is they will.

Compare that to a lot of the whining in and around alt.net these days about the tendency of some members to vocally and publically call for reforms in Microsoft. Those people are standing up for what they think is right, not being "mean", not being assholes, but being spokesmen for an issue that they (and I) consider important to a wider community.

Sometimes it takes a very public beating to enact change in a system that adores its status quo. Sometimes you need a fighter. Give that some thought before you next call someone who is on your side a loudmouth or worse.

author: Scott C. Reynolds | posted @ Friday, March 13, 2009 2:12 PM | Feedback (5)

Beginning Objective-C for the C# Guy


So my new language of the year is going to be Objective-C and Cocoa/CocoaTouch. This is actually a new language and a new IDE and a new platform and, well, everything. I've decided to document much of what I'm doing along the way. As you know I switched my main platform to Mac last year and have been doing my .Net development in a Virtual Machine. This has been great, working out extremely well, but part of what I wanted the Mac for was to branch out and explore some different ways of writing applications. Studying a new language is a great way to get a different view of how to accomplish programming tasks, and seeing how things are done on other platforms can only increase your skills as an application developer.

So with this post I wanted to go over some basics, compare some things in .Net to Objective-C, and kind of give a quickstart.

Environment Basics

Some housekeeping terminology. XCode is the IDE you use out of the box to develop mac applications. It's a full-featured IDE that comes installed on your mac. In some senses it's not nearly as mature as visual studio, and I find myself missing vs and particularly Resharper, however, you also don't have to pay $2k for your dev tools, so, worth the tradeoff.
Objective-C (ObjC) is the standard language of choice for developing Mac applications. However it's not the only one. There is support for Java and Ruby in Cocoa and, of course, OSX being a *nix system, you can write programs for it in any language really. But for the purposes of talking about Cocoa/Mac dev, we're talking mostly about ObjC.
Cocoa (and CocoaTouch) is your Mac development equivalent to the .NET framework basically. It provides a lot of framework base for mac development as well as the stuff that supports GUI hotness. CocoaTouch is Cocoa for iPhone/iPod Touch environments, with some differences in what it has and what is supported.

Objective-C Basic Information

Objective-C is a "strict superset" of C. This means that all valid C code is valid Objective-C code. Objective-C is an OO language. The Objective-C OO is more like SmallTalk OO than the C++ style OO you are used to. In Objective-C you talk to objects with messages rather than calling methods. For instance the Objective-C code:
	MyType *myType = [[MyType alloc] init];
	[myType myTypeInstanceMethod:10];
	

Is essentially the equivalent of the following C# code:
	MyType myType = new MyType();
	myType.myTypeInstanceMethod(10);
	

So basically the method calls you are used to in C# turn into message passes in the [] brackets.

The interesting thing about the messages is that you can send messages to an object that may not actually handle them. This is a dynamic typing feature borrowed from Smalltalk. You can choose to handle the message, or forward it on, but if you don't do something with it you will get a runtime, not compile error. (xcode will give you a compile warning though to protect you from yourself a little.)

Some structural differences that might trip you up: if you have ever done any c/c++ you will be familiar with the practice of separating declaration from implementation on classes and methods and such. This is a luxury that is easy to overlook in C#, where you don't have to do that. So in Objective-C you have to do that, but the thing you may trip up on is that the declaration of a class is called an "interface". This is different from what you think of as an interface in C#. In Objective-C the "interface" is the signature of the class being implemented. If you want a C#-style interface that let's you do composition over inheritance, you are looking for a "protocol" in Objective-C.

Declaring and Implementing a class in Objective-C:

@interface MyObject{
	
}
-(void) myTypeInstanceMethod:(int) integerMethodParam;
@end

@implementation MyObject
	
-(void) myTypeInstanceMethod:(int)integerMethodParam
{
	//do stuff
}
		


Another thing you may be noticing looking at the code above is the slightly odd method signature. Let's break it down. The - (minus) means "instance method". A + would mean class method. Class methods in Objective-C are like statics in c# but they're inheritance-friendly and can be overridden. (void) is your return type, just like C# but with parens. Then there's the method name, then after the colon you have the parameters. You add more parameters by adding more colons:
		-(void) myTypeInstanceMethodWith3Params:(int) integerParam1:(int)integerParam2:(int)integerParam3
	

One thing you aren't noticing is a visibility modifier. As far as I can tell, there's no such thing as a private class method. You can do some tricks to hide it from the compiler, but because the class methods are really just there to respond to messages the object receives, if you send a message called the same thing as a class method it will get handled.

Unit Tests

If you're at all like me, hooking up tests is pretty second nature for you in c# now. Being able to write tests to verify my code helps me learn new things in new languages. The testing story is interesting in xcode, especially if you are used to any of the standard test runners and frameworks in .net.

XCode 3.1 comes bundled with a unit testing framework called OCUnit. OCUnit was a third-party open-source project that Apple got behind and took over responsibility for. (wait you mean the vendor doesn't *have* to write their own test framework?) The mechanics of testing in xcode are a bit obtuse at first. I went here to figure out how to actually set up a testing system, and being totally new to the environment, it took me a while. But follow the steps and you'll get there.

One thing to note is that there is no concept of a "test runner" like you have with tdd.net or resharper or mstest. In XCode, to do tests, you set up a new build target that understands that it will be running tests. Then tests run as part of your build. That's it. You build, it runs tests. All of them as far as I can tell. If a test fails, you get a build error. At first this feels like a much lamer experience than say the R# test runner, but on the positive side there's no skipping tests and you do get the error inline with the code window. Either way, it takes some getting used to. As a side note, my homesickness for R# really kicks in as my "tdd workflow" in ObjC is clunky and very slow right now.

Your tests in OCUnit are a convention-based thing, unlike a metadata (attribute) thing in .net. Your test methods must be void and must start with "test". You also get a setup and teardown. This is a test fixture I wrote for doing the first Project Euler problem. It's not really my typical style (I haven't bothered trying to get a BDD flow going yet) but it shows the basics:

@implementation eulerproblemonespecs
EulerProblemOne *newProblemOne;
-(void) setUp
{
	newProblemOne = [[EulerProblemOne alloc]init];
}

-(void)tearDown
{
	[newProblemOne release];

}

-(void) testItShouldFindMultiplesOfThreeAndFive
{
	//doing it with a variable
	bool isMultiple = [newProblemOne isMultipleOfThreeOrFive: 4];
	STAssertFalse(isMultiple,nil);
	
	//passing the message inline
	STAssertTrue([newProblemOne isMultipleOfThreeOrFive:3],nil);
	STAssertTrue([newProblemOne isMultipleOfThreeOrFive:5],nil);
	STAssertFalse([newProblemOne isMultipleOfThreeOrFive:23],nil);
}

-(void)testItShouldSumMultiplesOfThreeAndFiveInARange
{
	STAssertEquals([newProblemOne sumMultiplesInRange:0:10],23,nil);
}

@end
		

No other ceremony required other than the naming. In the declaration of the test fixture you just inherit from SenTestCase and go.

So, to close this one out, I'm having a lot of fun learning this new environment. And it is interesting to care about memory management and performance again (very important for iPhone dev). And it's interesting to think about OO in a different way. If you haven't chosen a new language for the year, and you have the ability to try it, I'd say give ObjC/Cocoa a shot. Now is as good a time as any to learn Mac/iPhone dev, market share is going up and the AppStore is kicking. Plus maybe you'll learn a little something from a development community that values user experience at a very high level which, let's face it, is not a priority in the Microsoft ecosystem. Trying new things and delving into new communities can only be good for your career in a down economy as well, so what are you waiting for?

Technorati tags: ,,

author: Scott C. Reynolds | posted @ Thursday, February 05, 2009 12:52 AM | Feedback (0)

On Teaching, Learning, and Being Honest With Ourselves


Preamble: I'm not an expert teacher or mentor. I practice all the time to get better. Much of what you are about to read comes from personal failings in this arena, as recently as a week ago. This is an open letter to all who would teach.

I've been seeing this sentiment going around in various forms, and it's troubling me. Somehow we've gotten it in our heads that it's not okay to accept the fact that people are not all at the same level of knowledge and ability. Somewhere along the way it became taboo to talk about people being elite, and people being beginners, and that it was imperative to teach and mentor and task people in a manner appropriate to their level. Somewhere along the way it became not only acceptable but encouraged for anyone to go forth, call himself an expert, and attempt to teach a crowd.

Let me disabuse you of some notions you may have gathered from blogs and mailing lists: people *are* at different levels. There are people that are smarter than you, and me, and everyone else. There are people that are more adept with a particular technical skill. There are beginners. There *is* such a thing as a junior developer, and he does a different job than a senior developer. All of these statements reflect the natural order of things. We are not all the same. That's a good thing, and if you think it's not, you are naïve.

Treating and tasking a junior developer the same as a senior is detrimental to productivity and detrimental to the growth of that developer. A novice is a novice no matter how you choose to describe it, and what a novice can do is vastly different than what an expert can do.

Teaching and the Dreyfus Model

If you are unfamiliar with the Dreyfus Model of Skills Acquisition, take a second to go read up on it real quick and then come back.

Ok, now we have a model (and programmers love models) for what each stage of learning looks like. Keep in mind the Dreyfus Model applies atomically to a given skill. You can be an expert in C# and a novice in Ruby. This resonates with everyone right? Ok so stop trying to put everyone in the proficient stage of every skill. It's not reality. We all fall into different buckets of the Dreyfus Model for every single skill that we practice and we only advance from one to the next linearly. You can't make a beginner skip steps by pairing him with an expert, and you certainly can't make him skip steps by forcing expert-level work on him. Beginners need rules and boundaries. They need clearly defined tasks and clear context (in such case as they even care about context, which they typically don't). Think of Iron Chef vs the line cook at your local chain eatery. The latter needs explicit recipes to make standardized food. The former needs only a table full of random ingredients to create something amazing.

This leads into three discussions: first - not everything can be taught to "beginners" and targeting the "beginner" is a farce. Second - when you attempt to teach, you must properly identify your target audience on the Dreyfus Model and set expectations accordingly. Finally - not everyone is cut out to teach.

Let's deal with the last one first because it's the one that will make the most people stop reading, so I want to save you some time. The old saying "those who can, do. Those who can't, teach" is ingrained with a kernel of truth (no offense to teachers, for whom I have the utmost respect). Remember that the Dreyfus Model is atomic per skill. Teaching a given skill is a skill. If you rank as proficient or better with say, C#, you can talk about it with authority sure, but you do not automatically gain the skill of being able to teach your fellow man. Teaching is not telling. Teaching is a vast array of skills related to communications, psychology, sociology, and technical proficiency with the subject matter. Some would say that at certain levels you can teach a subject without "expert" skill in said subject, as long as you have high skill levels in the other aspects of teaching. I can buy into that, because it's a bleak world indeed where only experts in a subject can teach it.

Bottom lining it for you - not everyone is cut out to teach. Sorry. If you have a strong desire to be a teacher then don't worry, because you can practice and gain the skills required (I believe Malcolm Gladwell talks a lot about gaining expertise through practice rather than innate ability in his new book Outliers, which I have not yet read but it is in my near future based on friends' recommendations). But if you go about teaching with the outlook that simply being proficient in a subject makes you qualified to be a teacher, then you are doing a disservice to those you wish to teach. (And replace "teach" with "mentor" or any other such verb at your leisure, dear reader)

Secondly - Define your audience appropriately and set the appropriate expectations. If you wish to teach something to "beginners", first define "beginner" in what skill. Most tech books do a pretty decent job of this, particularly the O'Reilly Head-First Series, which explicitly lists in the beginning of each book what you will and won't get from this if you are at a given level. This is called managing expectations, and it's important both for the teacher and the student. I recently did a full day workshop on TDD aimed at "beginners" and learned this lesson the hard way. Beginner casts a very wide net when both parties' expectations aren't managed appropriately, and you spend much of your time either derailing the subject with questions you assumed were already known, or alienating people because you aren't answering questions that they came to the table with. We came to the table with a set of stories around website registration, just registration, what we thought was a very small problem domain. In the course of the day we implemented the code for 1 story. The rest of the time was spent explaining concepts that we wrongly assumed were in play, like SOLID principles (among other things). And the vastly different levels of each of the 80 or so attendees meant that we felt the need to get to the lowest common denominator with everything. This means that the smallest subset of the audience was served well, and the rest, while they probably got some value from the event, left having not had their expectations met.

Thirdly - "Beginner" may not be a good audience for some concepts that you intend to teach. Again, look to the Dreyfus Model and ask yourself: "Am I able to sum this up into essentially recipes and step-by-step instructions with defined rules?" If the answer is "no", then "beginner" is not your audience, and you will leave them confused. Looking back to some of the feedback we got from the TDD Firestarter event, this was the case for a lot of people. Presenting TDD/BDD with a lot of "it depends on context" type guidance is not appropriate for beginners. We did those people a disservice and probably confused them to the point where they aren't going to be testing as a rule any time soon. This is obviously counterproductive in terms of the goal of the event. We even had reports of people being disappointed that our samples were in nUnit rather than MSTest because it didn't occur to us that an actual beginner may not be able to convert one type of sample to another just based on attribute names. These are the kinds of things that you run into when targeting "beginners" for teaching, and you need to be both aware of them and willing to overcome them if you intend to teach to this group.

Accepting Some Realities

If I had one point to drive home to aspiring teachers of technology it's: "don't mismanage your own expectations". You must understand your audience and the level at which you really intend to teach in order to be successful. And you must understand whether or not you have the requisite skill level to teach that subject matter at that level. I don't mean at all to discourage budding mentors and teachers, I just want to give you the straight story so that you can more effectively put yourself in that role and not come away disappointed and not leave your students bewildered.

On to the labeling issue. Some people are beginners. Some are experts. It's okay to call them that. Because it's honest. I heard recently in a mailing list discussion that some people may take umbrage to being labeled as a beginner. That's unfortunate but true. However, my experience has been that those people haven't set their expectations and egos to the level appropriate for being a student. In other words, some people don't want to be taught, so don't bother until they are ready, and you will save yourself a lot of stress.

Finally, teaching is a huge burden to bear, and you need to understand this before you take on the responsibility. I know the draw of doing a codecamp talk every other month is a big one, maybe you'll get some micro-celebrity, maybe you'll get an MVP award, but you can't be a hit-and-run guy and be a teacher. I'm not saying don't do codecamps, because you should, but I'm saying accept the responsibility of the role and tailor your message to the format and the audience. Don't go to a 1 hour codecamp talk with the intention of teaching TDD+SOLID+IOC+MVC+whatever else. It's not reality and you won't be giving your audience anything they can build on. Anyone that can glean a ton of value from a talk that big and that short can get that same value from a blog post. Don't try to be a hero, don't try to be sexy, just be honest, teach within your capabilities, and manage expectations appropriately on both sides. Teaching is a rewarding practice, but it takes effort, and you should strive to improve in the teaching skill as relentlessly as you strive to improve your technical skills if you truly want to be a teacher.

One final thought - I know *truly* beginner-level 101 courses and talks aren't sexy and won't get you the notoriety, but there is a need for them. Do them. All boats rise with the tide but the water level is lower than we think sometimes. Let's work together to bring up the baseline.

author: Scott C. Reynolds | posted @ Friday, January 23, 2009 12:11 PM | Feedback (0)

TDD Firestarter Wrapup


This weekend Sean Chambers and I put on a day-long testing workshop at Microsoft in Tampa, FL. I want to thank all the attendees for giving up their Saturday to come out and learn about testing.

Special thanks to Joe Healy for putting on the event. He deserves a lot of credit for allowing us to come and use his space and eat his food and let us talk all day about something that wasn't even Microsoft-specific. It's because of the guys like him (and others) out in the trenches that I still have hope for Redmond.

Also major thanks to Cory Foy, Rob Eisenberg, Chris Bennage, Josh Schwartzberg, Scott Densmore and Jose Bueno for helping out with questions, running cameras, and providing moral support.

This event wouldn't have happened if it weren't for Sean, I checked out on the planning during my multi-month headache, so send mad props his way.

Some housekeeping from the event, I promised to throw up some links for some of the stuff we talked about.

First up is unit testing frameworks - all of which will do what we showed in the demo:

Also there are plenty of unit testing frameworks for non-.net code. Search for [language]+Unit Testing in Google and you can find them for JavaScript, SQL, Java, Lua, Objective-C, C++, F#, Ruby, and just about anything else you're using.
Next up we have Mocking/Isolation Frameworks: And don't forget, you can always quickly write your own test doubles and fakes.
Testing the UI: And there are many more, these are just the ones I rememberd mentioning. Remember, if you need to test it, there's a way to do it, it's just about finding the right tools.

Additionally we talked about Continuous Integration, and mentioned that it could be done with tools such as TeamCity, CruiseControl.net, Hudson and Team Build with Team System.

If there's anything I forgot to include post a comment and I will update. Thanks again to everyone who came, and I look forward to doing it again!

author: Scott C. Reynolds | posted @ Sunday, January 18, 2009 11:24 PM | Feedback (0)

TDD/BDD Firestarter


This coming Saturaday, January 17, Sean Chambers and I, in conjunction with Microsoft, will be hosting a day-long set of workshops centered around testing. Admission is free, so come prepared to spend the day getting intimate with testing!

The day will begin with a deep-dive code-oriented beginner's course to TDD (with a context/specification slant) continuing after lunch with a look at more advanced testing topics, including mocking, database integration testing, and testing WPF applications. Along with Sean and I, Cory Foy, Rob Eisenberg, and Chris Bennage will be presenting.

Whether novice or advanced, you are sure to find value in the day's sessions, so go here to register and we will see you in Tampa on Saturday!

author: Scott C. Reynolds | posted @ Saturday, January 10, 2009 9:30 PM | Feedback (0)

Creating a Culture of Responsibility


Shooting from the hip a little here, please to bear with me. Also, turned out a little lengthy. Sorry 'bout that.

I hear a lot about (and talk a lot about) the idea of a culture of quality. This is, arguably, where we would all like to be. But the relentless pursuit of continuous improvement that defines a culture of quality requires a few things to be in place beforehand. Quality at an organizational level (or team level, or personal level) doesn't just happen. It has to be sown into already fertile ground.

One of the bits that must be in place is a clear sense of responsibility at every level. If the members and teams within the organization are not prepared to be responsible for the successes and failures of the organization, there will be no necessary support for a continuous improvement practice. A culture of responsibility necessarily precedes a culture of quality.

In lean manufacturing, andon is a process in which the line worker has the ability to in some way stop production and alert supervisors and other line workers to a quality or process problem in production. Every line worker is given the responsibility of triggering the andon system (hitting the big red stop button) when they see a problem. The entire line is given this responsibility, and therefore, if a quality control issue makes it out the door, everyone from the design engineer to the guy putting the widget in the box is responsible for the failure.

Creating and fostering a culture where an employee will accept this mantle of responsibility and embrace it is not an easy task if you look at classic American management techniques. In fact, you will often find that the average American corporation is more than happy to foster a culture that eschews responsibility in favor of protectionism. Trying to buck this trend can get you in trouble; not everyone is open to change, even good change. As I have put forth the premise that a culture of responsibility is good, however, we're going to explore how to alter our management techniques to help bring one about. ;)

There are two primary enemies of the culture of responsibility: fear and lethargy. Fear I can help you with now, lethargy is a motivational concern (and not everyone can be motivated by means at your disposal).

The fear factor comes in many forms. Fear of making mistakes is a big one. Conflict aversion is another. People can be unwilling to go out on a limb because they don't want to be wrong. This can be personal pride or a desire to maintain some illusion of authority to others, or a combination of the two. These fears lead people down the road of abdicating as much personal responsibility as possible in favor of a CYA-focused strategy.

There are practices that we tend toward in American corporate culture that help engender these fears. What I'd like to do is explore a handful of them, and offer some alternative strategies. Then I would love to see this conversation continue in the comments, as I know many of you are managers or leaders of your own organizations. Keep in mind, this is a reflection of my experiences, I am not claiming in any way that any of the proposed alternatives is THE ONE TRUE WAY.

Measurement and Perceived Productivity/Quality

If you have ever been paid by lines of code, or heard of someone who has, you know where this is going. Now don't get me wrong. I am all for measurement and metrics. I am often heard to say "You can't improve what you can't measure." But you have to measure the right things, and I think we all know that KLOC is not the right thing. But there are other, more subtle, poor measurements being made.

Let's look at defects for instance. Can you appropriately assess a programmer by defect count? No. There are many more factors to consider. What is the nature of the defects? Are there repeated patterns? How do they relate in context of the code produced around them? Are they a result of sloppy coding, or of lack of context needed to write appropriate tests? These are all things that matter when you want to measure a developer using defects as a metric. These are all things that are not surfaced by a simple count, or, maybe worse, a ratio of defects to released features. A simplistic look at defects is no better a measure (and gives no more context) than counting lines of code produced.

Sort of the inverse of defect measurement is measuring productivity by numbers of tasks done or features implemented. Again, this cannot be boiled down and completely lacks context. Unless you have reached a point where you can define a standard unit of work for what the term "feature" means, a number of features is meaningless. Similarly you can't do a strict measure based on "stories" or "use cases" or any other amorphous bit of work.

As an alternative to these measurements, you can measure throughput at a larger, team-oriented scale. Establish a baseline for the amount of work that can be completed by a team in n time, where the amount of work is measured in terms of complexity rather than hours or items. This number will not come by magic, you need to build toward it and coax the team toward achieving their full capacity. But over the course of a relatively small window of time, you should see a leveling off of throughput. Once you have this baseline, you have a metric from which you can make assessments. Estimate complexity for new work only, do not assign complexity to rework (defects). In this way, defects that creep into a development cycle will naturally decrease the throughput on new work, and you use this deviation as an indicator of either quality downtrends or productivity downtrends. Conversely, you may see positive deviations from this baseline that will indicate a throughput, capacity, or quality increase from the established norm. At the end of the day, the importance to the business is predictability of outcomes, in terms of throughput, cost, and quality, at a level more macro than an individual developer (in teams greater than one of course). You can further use this new understanding of team throughput to properly assess when work will be completed, when it's time to add capacity (more developers or testers), and what sacrifices to make when priorities change.

This of course doesn't absolve you of the responsibility of managing an individual's performance. It does, however, give you the ability to spot problems when they are happening, and then look at the surrounding context. You learn from measurement that defects are causing throughput to suffer inordinately, then you investigate the defects to determine the proper course of remediation. It may turn out that a defect is caused by the developer needing some help with programming-related skills, or that there was a communications issue and that more than one party is at fault. A defect can be caused by improper specification or lack of appropriate tests. But there will always be defects, so it's important to know how they are affecting throughput before chasing every one down. The same is true for number of features implemented. If throughput drops because a developer has failed to deliver the expected amount of functionality, then you start to delve into the cause at an individual level. But first you have to have established a baseline so that you actually know that a reasonable expectation was in place.

Anti-collaborative Tendencies

The gold standard in corporate IT development is one person, one task. The idea that a team of people could better perform a task that is traditionally seen as an individual exercise is anathema to many. One business analyst talks to one customer. One programmer writes the code for one feature. One tester tests that feature. This is the mindset that leads to the thinking that adding headcount increases throughput by a correlating amount. Anyone in software for any amount of time knows that this is patently false.

Furthermore, this anti-collaborative environment is detrimental to both throughput and quality. It encourages the CYA silo-building that we see so often, because when the responsibility of a task is shouldered entirely by one individual, it triggers our human defense mechanisms that cause us to play the blame game, find scapegoats, and make excuses for poor performance.

As an alternative to this, I encourage the adoption of the One Team philosophy (possibly the most valuable SCRUM principle I've encountered). Collaboration and open communication, to the point of transparency sometimes, is necessary to ensure that people feel safe taking responsibility. It may sound paradoxical, but spreading responsibility among many increases the willingness of the individual to accept more personal responsibility. This is because shared responsibility allows us to lower our bulwarks and concern ourselves with the success of the team rather instead of focusing on our personal protection only.

Practicing the One Team principle takes many forms. At minimum the planning processes need to involve the line workers (coders and testers) to get accurate estimations of complexity. I am an advocate of pair-programming on the line to increase collective code ownership and encourage collaboration, as well as having the side effect of great potential gains in quality and completeness of code. Code reviews have a similar effect when done appropriately, without the benefit of in-the-moment interaction. In fact, anything that increases collective code ownership will serve to reinforce a culture of responsibility. When many people see the code, not only is there more of a chance that quality problems will be caught before going to production, but the incentive is higher for an individual to take responsibility for the code because he knows that he shares the blame for defects, even if the defect wasn't introduced by him. Collective code ownership is one of the most important things to have in place before expecting that quality issues can be handled in the vein of an andon system.

Mistakes, Experimentation, and Learning

It is typical in corporate culture that experiments and mistakes are to be avoided in favor of known paths and rote repetition. The aversion to making a mistake is a strong motivator in the abdication of personal responsibility for quality. Mistakes and experiments are seen as costly at varying degrees, and learning is seen as something you should have done prior to submitting your resume. People live with the fear that a mistake could cost them their job, and particularly in a down economy, there's a lot of that fear to go around. Unfortunately this means that there is no room for a person to take responsibility for improving a process, learning or teaching a new technique that may be on the cutting edge, or accepting and fixing a quality issue.

Toyota embraces mistakes and experimentation as learning and growth opportunities, and encourages a system where people are safe to experiment and make mistakes. Not haphazardly of course, there is a process required to prove the value of an experiment, but once the experiment is underway a mistake is not seen as a failure but as a necessary step toward a successful outcome. Similarly, Google has the much-vaunted 20% Time which is an extreme example of an experimentation culture, where justification is not requisite, but many Google features and apps have been born of this policy. In both of these companies, employees are empowered to experiment, and empowered to make, own, and improve because of mistakes. By most measures, these companies are both wildly successful and offer high-quality products (though GMail is suspect at times...). There are lessons to be learned here.

Now don't for a minute think I'm advocating the wasting of company resources for self-entitled experimentation. I have been guilty of this and so have you, but it is most certainly not appropriate. I am however advocating creating an environment where justifiable experiments are encouraged, and where mistakes are treated as learning opportunities (openly) rather than collected as annual review fodder. Encourage team members to spike ideas for a couple of days before hard decisions are made. In the long run this will at the very least have a net zero effect on productivity. Encourage team members to objectively analyze mistakes and quality issues and come to conclusions about their causes and solutions. Make sure there is a safe environment for reflection on failures to ensure that employees will take care to prevent failures from making it to the customer.

Conflict Aversion

Many people will hesitate to point out quality issues that may not have been their own out of fear of conflict with a team member or other collaborator. Many people will hesitate to suggest process or product improvements because they fear an argument with a manager, or a hierarchical structure prevents them from crossing boundaries. This is obviously a major impediment to continuous improvement, as nobody is willing to step on toes to take the responsibility of improvement on.

When we talked about One Team, we talked about putting in place methods that will create an environment more conducive to the open collaboration required for people to feel safe expressing concerns of quality or process. However, organizational issues beyond the immediate team can cause more potential conflicts that people are just unwilling to deal with.

Solving this problem requires a multi-headed approach. First, the development team needs to know that they are a part of, not separate from, the organization as a whole. We/They attitudes toward the larger organization prevent the team from putting the needs of the organization above their own sense of entitlement. Only by adopting the mindset that the team is a cog in the larger machine will the team be able to think organizationally. As a leader, it is your job to make sure the us/them wall gets broken down.

Secondly, you must become the advocate for the team to the rest of the organization. If you create an atmosphere where your team takes responsibility for the whole organization and brings you a quality concern or process improvement idea, it is incumbent on you to take that as far as you can in the rest of the organization. You remove the conflict from the shoulders of your employee and put it where it belongs, with you. If a developer thinks he is going to have to fight a losing battle with sales to get something changed, or worse, thinks that there is no conduit for communication across these boundaries, then he simply won't care about anything beyond his IDE, and that is not going to lead your team toward adopting a culture of responsibility.

I think I've carried on long enough about this for one blog post, but I'm interested to hear what you think. As a final note, it's not easy to change some of these long-engendered attitudes in a corporate culture, nor is it always possible. However, if your goal is to be a change agent and create a culture of quality, you must first put into place the changes that will allow a culture of responsibility to evolve.

author: Scott C. Reynolds | posted @ Wednesday, January 07, 2009 3:07 AM | Feedback (0)

Lean/Kanban Software Conference in Miami


Just wanted to put it out there for my fellow Floridians that the Lean & Kanban Conference is going on in Miami, February 18-20. Space is strictly limited so register today for your spot. I'm currently trying to make my own arrangements to attend though, so don't take my spot!

If you are interested in taking what you know about software development and looking at it through the Lean-O-Scope, this is where you want to be. Among many distinguished speakers will be Dave Laribee, who has really interesting ideas on bringing pull systems into an Agile shop, and modifying the way we think about and use our tools (source control, CI, etc) to achieve a release-per-feature workflow.

Corey Ladas will be there to speak as well, and if you are at all interested in this stuff you should be reading his blog. If you want to catch up on his writing in one nicely packaged chunk, also check out his Scrumban book.

So if you're in Florida, there's really no reason not to go, and if you aren't, then you're probably one of those people that wishes you were, so come enjoy some beautiful Miami weather in February and escape the snow.

author: Scott C. Reynolds | posted @ Tuesday, January 06, 2009 2:03 PM | Feedback (0)

On Your Health and Your Career


People haven't really heard from me in a while, and there's a few reasons for it, but I'm about to talk about the major one.

Sometime around the Kaizen Open Space in Austin, just a little before actually, I stopped being able to look at my computer screen. On an average day, 5 to 10 minutes looking at the screen and I wanted to gouge my eyes out. I was getting severe headaches. I was extremely tired, or at least, my eyes felt like they were. I was irritable. My eyeballs itched. It sucked man.

So that meant very little computer time on most days. No twitter. No blogs reading or writing. No writing code. Basically I kept the time limited to email that I needed for work, and the bare minimum time in visual studio. Since I'm all manager-y now, I don't get to write a lot of code anyway, so that kind of just worked out. During that time a new WoW expansion came out, and trying to keep up with my friends was a chore, and most of the time I was online I was actually not looking at the screen. (Which is a shame, because Blizzard put a lot of work into it and it's very visually stunning.) When I did have to spend non-trivial time in the IDE, I just dealt with the pain.

So this has actually been happening off and on to me since late 2004. At one point I bought grocery-store reading glasses that seemed to help just so I could write code and get through the day. But the problem kept going away after a couple of weeks, and, me being me, I just let it go. But this time it was way worse than ever, and going on 2 months duration. I broke down and finally went to an optometrist (with much prodding from a close friend).

Now comes the part of the story where I start coming to grips with the ravages of time. Having spent all my life with perfect vision, I was unprepared for an eye test where I couldn't read the bottom two lines of the chart. The tech actually got impatient with me because I stubbornly sat there trying to will my eyes to focus on those letters, but it didn't happen. Long story short: I had somehow gone from perfect vision to nearsighted, farsighted, and a slight astigmatism. Were I the designer of the human body, nearsighted and farsighted would cancel to an acceptable middle state. Anyway, I now am bespectacled at all times except when sleeping. Advancing age and upwards of 15 hours of computer time per day were to blame said the doctor man, and so my glasses also have some special whosamawhatsit on the lenses specifically for computer work.

Were it not for the fact that I need the computer to live I might have been content to let this eye thing go until they got fed up and leapt to their deaths leaving me with gaping sockets. But now, well, last week I paired all day 2 days in a row and was ready for more. And the headaches are gone. And I don't feel tired anymore (not from sitting around on the computer anyway). And while I'm still not completely adjusted to them (my eyes are still pretty fatigued by the end of the day), I know the glasses are helping. And I'm kicking myself in the ass for ignoring the problem for so long.

Your health affects your livelihood brothers and sisters of the sedentary knowledge-worker persuasion. I know when I put on a few pounds it's reflected in my productivity and I can guess what the scale will say by my average level of energy change over the course of a few days. And when I'm not getting enough exercise my mood is unpredictable, my irritability and anxiety are high, my posture suffers and my time at the keyboard becomes physically painful. And when I eat poorly for a few days my code quality measurably suffers. And when my eyes don't work, well, I'm not good for anything at all.

So, in this upcoming time of annual stock-taking and resolution-making, this is my reminder to you and me that your health matters, and your productivity as coders and managers and members of society is very closely linked to your physical well-being, so keep it in mind. And stop pretending you aren't getting older, and make those doctor appointments to keep things in order. You are the most legacy system you'll ever work with, so you need to take extra care to keep it performing optimally.

author: Scott C. Reynolds | posted @ Sunday, December 14, 2008 1:59 AM | Feedback (0)