Remote Pair-Programming


AgileApprenticeshipDesign processSoftwareTestingThoughts

Seems like Pair Programming is “all the rage” lately in my circles. I haven’t exactly done it before but after hearing about the success and rapid knowledge growth amongst those that pair program…I was almost dying to try it! Especially after i saw David Chelimsky and Corey Haines at WindyCityRails in Sept 2009. I saw them pair and do BDD with Rspec/Cucumber and it was so fascinating, It was like I was watching a ballet as they hopped from RSpec to Cucumber and back and forth. I was like, wow…I wish I was that good! I would have paid good money for a recording of that so I could watch it again and again! I see Corey Haines traveling around pairing with people too. Some people get together and play cards, but Corey gets together to code!

So ok, I like code, I like people, I want to try it! I live a little south of Chicago so its a long commute and it seemed everyone was so busy to pair in person when I asked. I asked on Devchix mailing list for suggestions on how to do pairing online. I had found a few, and the group had some good suggestions. I even had a volunteer to try it with me! This week aimee and I set a few hours aside to try it and see if we could do it!

This article was also sort of “paired” as it was written from my perspective with input and suggestions from aimee!

We asked on Devchix mailing list for suggestions on how to do pairing online. I had found a few, and the group had some good suggestions. I even had a volunteer to try it with me! This week aimee and I set a few hours aside to try it and see if we could do it!

After introductions on Skype we set about getting a shared environment in which to code together. Ideally, we wanted some kind of desktop sharing so we could run tests, console and editor.

We had heard of a few tools and got suggestions from the devchix list:

IChat desktop sharing – we couldn’t get this to work, we did different things and it would appear to connect but then it failed. I tried to mess with settings for Sharing on mac, but nothing doing.

Rio seems to be a library to make collaborative apps, not to use in a pair programming environment.

BeSpin was hard to use.. we couldn’t figure out exactly how to use it. It almost seemed to offer to import the git repository we were working on, but then it said it only supports Subversion and Mercurial, not git.

SubEthaEdit worked but we would have to open each file individually and share each file… unless I was missing something. This would be fine for collaborating on a single file but then we could not share the test runs, terminal commands or view the browser together.

Etherpad – we didn’t end up trying this but I have used it before to debug some code or try out ideas with a friend. They recently got bought by Google, so it would be interesting to see what they do with it. This would suffer the same limitations as SubEthaEdit in that it’s just a text editor.

GoToMeeting (which is $40-50/month) its a little steep for the open source work I want to do. But people say it works really well.

VNC and Unix Screenaimee had used this successfully before but since we weren’t on the same network, just our laptops at home, we weren’t sure it how we could make it work easily.

Then we came to TeamViewer which worked brilliantly! We shared desktop and I could type in aimee’s console window, see the tests running and type in textmate. Even with aimee on her Dvorak keyboard and I on Qwerty! I could type fine but couldn’t copy/paste with keyboard shortcuts so I used the mouse to copy/paste and it worked fine.

All in all, it was an awesome experience and I picked up on a few tidbits of knowledge from aimee on git, and rake! I had some bits of code from another project i was able to quickly copy/paste and get us rolling. We had a few discussions about coding style as we went.

Since aimee was more familiar with the codebase, she mainly wrote the behavioral specs and I wrote the code to satisfy them. We plan to switch around next time, when we pair on a different project that I’ve been developing for a while.

Book Review: "Refactoring in Ruby"


BookDesign processEventsIntroductionsRubyTestingTips and Tricks

“Refactoring in Ruby” written by William C. Wake and Kevin Rutherford.
Published by Addison-Wesley

This is more like a “workbook” then a “how to write awesome code” book. You can download the code from github http://github.com/kevinrutherford/rrwb-code and you will find tests/specs for the exercises.

The book is arranged in three parts, The Art of Refactoring, Code Smells, and Programs to Refactor.

There are explanations of “code smells” which are one characteristic of code that could be improved. Some of them are long parameter lists, unnecessarily complex, global variable, feature envy sections, etc. One thing I find interesting is the “How did it get this way?” section. It gives some insight into the thought process and reasoning behind the smell. I think this is good, as programmers our ego may be rather miffed to hear “This code stinks” but with some reasoning, it makes the pain less and I think firms up in our minds when this happens again, to do it this other way. I always want to know why when someone says I could do such and such thing better.

In addition to the code smell examples there are three programs to refactor in the end of the book. In a conversational tone, it walks through and gives some hints on what needs refactoring. Its almost as if you had a pair programming buddy working with you and identifying in small chunks what can be improved. This is definitely something I want to work through more carefully.

What I find odd, is that not all the code smells have code examples. The inspiration for the book I think is the Martin Fowler book “Refactoring Improving the design of Existing Code” which has examples for every code smell. Maybe Ruby smells less than Java? Or those fixes are really trivial? I don’t know. Overall, this is a great book and is certainly worth the price and investment and you will be a better programmer because of it!

Women Who Tech TeleSummit


BusinessEventsPresentationReviewsThoughts

The Women Who Tech TeleSummit was like a gift that just keeps giving, and giving and giving. I attended three and a half panels and the after-party and discovered about twenty progressive, interesting businesses, news organizations, non-profits and email lists. Quick disclaimer, I love this stuff more than I love technology. I could eat ten progressive new developments in social justice for breakfast, every day. So my cup of tea may not be your cup of tea, but the fact that all of this is made possible by the agile new web technologies that devchix and women like us are building has got to be common tea. Eh?

Let’s start with the Launching Your Own Startup panel. The quote I can’t stop remembering is “Entrepreneurship is like jumping off a cliff and building a plane on the way down.” Also, that failure has lots of virtues: it makes you smarter, more attractive to funders, can make you fearless and more willing to jump that cliff. They all heartily encouraged anyone interested in starting a business to go for it. On a practical level, they all made sure their ideas had legs before quitting day jobs or abandoning previous businesses. They recommended an iterative business model with some focus on revenue from day one; recommended bootstrapping then going for advisors and then angel funding before going for VC money. They stressed researching VCs very, very thoroughly to make sure they understood your product and market or community, then selecting one you have a viable, personal connection with. They also recommended having business partners, for the value of differing strengths, but also because it makes you more attractive to funders, helps with your power balance with them. They all recommended Steve Blank’s book Four Steps to the Epiphany.

The next panel I attended was called The Feminine Mystique. (See this for the historical context of that title.) Essentially, this one was about the level of satisfaction women are finding in the life of technology work. Issues of work/life balance, of qualities of nurturing being undervalued in the workplace were explored. —There was a nuanced discussion at this point, by the way. We recognized that not all women are nurturing, etc. The value of mentoring was explained thoroughly, however, both in the men-tee experiences of the eminently successful panelists and as an undervalued management tool used to grow workers. We discussed promoting tools for shared parenting and increased time off for fathering, that had been introduced twenty years ago and were succeeding but lost favor in the rabid conservatism of the past decade – job-sharing, for example. We discussed the need to consider ourselves experts with less qualification than studies show we currently do, to create more parity with the way men determine themselves experts, and then act on that accordingly. (Men will see a list of requirements for a job they’re interested in, know they have only two out of twelve, for example, and confidently apply; women won’t unless they have ten, for example.) I feel however, that a little of both is in order on this issue: it’s important to re-define “expert” so that men who may be undeservedly claiming the right to that title are discouraged, just as it’s important for women who aren’t doing so to be encouraged. This translates into behaviors like speaking in meetings, etc.

The Video Activism panel. The panelists were from Youtube’s non-profit program, Witness.org and Free Range Studios. Basically they discussed different methods of persuading people to act, but their relationships to video were very different. I thought the most interesting aspect of the discussion was the striking contrast between Witness’ and Free Range’s work specifically. Witness is a global human rights organization, while Free Range is a San Francisco-based design shop that provides creative services for nonprofits and socially responsible companies. Witness often works with user-uploaded video, it’s often brutal and they don’t necessarily have control over issues of style or sound or pacing, whereas Free Range is in the business of crafting and producing video as part of larger, sophisticated campaigns. Both are very effective organizations, both discussed tactics for targeting people in concentric circles from most passionate and likely to act to least aware and engaged, but with widely differing parameters. Witness gave an example of a very graphic video in which Egyptian police beating a man was produced and released by the police themselves in order to intimidate others, but it reached the notice of human rights bloggers and so has been widely used as a resistance tool. It’s this combination of raw footage used by bloggers that creates the successful activism in Witness’s case. (Witness licenses footage on a sliding scale from their archive of about 3,000 hours of video; it’s frequently used by documentary filmmakers, journalists, grad students, etc.) Whereas the Free Range spokeperson gave an example of using stop-motion video, which is time-consuming and a little expensive to produce, in a campaign called save the bay. It was also very successful: they achieved their targeted number of email signups and their funding goals for an environmental impact study. But they were able to control every aspect of the video and the microsite on which it’s viewed.

I listened to a bit of the Social Media ROI panel, which hit topics like how you measure success depends upon how you frame your criteria, slightly tautological but the example given illustrates the power of the point. Presidential candidate Ron Paul used social media to try to win the Republican party’s nomination but didn’t (obviously). What they proposed, I believe based on interviews with Mr. Paul, is that he didn’t believe or intend to win, though of course he would’ve welcomed that outcome. What he wanted was to make sure certain issues were part of the debate and by using social media, he achieved exactly that. And hence, success. I only listened to a bit, though, because I was getting ready to travel to the after-party, which I attended and thoroughly enjoyed. The bar was laid back, they provided meat, vegan & veggie pizzas, it was a comfortable number of people, the discussions were friendly, and I met a journalist who works for the Huffington Post. On top of meeting five or six women programmers and Deanna Zandt, a prominent feminist organizer and technology consultant in New York who turned out to be one of those really nice, fun, shots-for-all-buyers. Good times, chix. Maybe we should try to get involved with next year’s summit, as an entity.

Links:

Women Who Tech Podcasts

Witness

That’s Not Cool

Knight News Challenge

RAD Campaign

Now Public

Deanna Zandt

RiseUp

The Story of Stuff

Free Range Studios

Berrett-Koehler Publishing

I Love Python: ReSTful DB CRUD dispatching using CherryPy


BookDatabasePythonServersThoughts

CherryPy has been one of my favorite Python tools for several years. It should be mentioned here that a ReSTful dispatcher could easily be written in web.py, or pylons as well, and even comes for free in the latest TurboGears implementation.

But if you’re looking for a small, easily manageable and extremely dynamic ReST dispatching solution without the heft of an entire web framework, I’m about to show you how CherryPy can help you in three different ways, depending on your model.

Assuming this mapping:

HTTP GET or HEAD = DB Read
HTTP POST = DB update
HTTP PUT = DB insert
HTTP DELETE = DB delete

Let’s also standardize on one common method across all examples, for determining the HTTP request type, and matching it to the function of the same name. Here is the full code snippet for accomplishing this task:

methods = ('OPTIONS','GET','HEAD','POST',
'PUT','DELETE','TRACE','CONNECT')

if cherrypy.request.method not in self.methods:
    raise cherrypy.HTTPError(400,'Bad Request')

# If request method is HEAD, return the page handler
# for GET, and let CherryPy take care of dropping
# the response body
method = cherrypy.request.method

if cherrypy.request.method == "HEAD":
    method = "GET"

http_method = getattr(self,method)

#print "HTTP Method: %s" % method

result=(http_method)(args,kwargs)

In our examples, we’re going to shorten this to:

http_method = getattr(self.m,cherrypy.request.method)
return (http_method)(args,kwargs)

All of this essentially determines how HTTP was called (GET/PUT/POST/DELETE), and calls the method in a class which exactly matches this name (self.GET(), self.PUT(), etc)
When you see this code, know that it’s just the HTTP method resolving code.

Now for the fun. Let’s look at the dispatcher options we have.

Way 1: A hard-coded URL pointing to fixed resources:

CherryPy can be used in a manner similar to this to establish a fixed URL, and corresponding resources, driven from predefined classes instantiated in the ‘root’ hierarchy:

import cherrypy

class ReSTPaths1:
	@cherrypy.expose
	def index(self):
		http_method = getattr(self,cherrypy.request.method)
		return (http_method)()

	def GET(self):
		return "In GET 1.."

class ReSTPaths2:
	@cherrypy.expose
	def index(self):
		http_method = getattr(self,cherrypy.request.method)
		return (http_method)()

	def GET(self):
		return "In GET 2.."

class ReSTPaths3:
	@cherrypy.expose
	def index(self,client_id=None):
		http_method = getattr(self,cherrypy.request.method)
		return (http_method)(client_id)

	def GET(self,client_id=None):
		return "IN Get 3, your client_id is %s\n" % (client_id)


cherrypy.server.socket_port=8081

root=ReSTPaths1()
root.client = ReSTPaths2()
root.client.address = ReSTPaths3()
cherrypy.quickstart(root)

Once this is running, the URL to invoke it looks like this:

http://localhost:8081/

http://localhost:8081/client/

http://localhost:8081/client/address/

http://localhost:8081/client/address/?client_id=34567

http://localhost:8081/client/address/34567

Output looks something like this:

In GET 1..
In GET 2..
IN Get 3, your client_id is None

If you’re new to CherryPy or Python in general, I’ll reiterate for you how we are calling the GET method in our class.

When we issue this request, we’re issuing what HTTP calls a GET request:

http://localhost:8081/

The CherryPy service above, listening on port 8081, calls the index() method on the root class. The root class was set to:

root=ReSTPaths1()

at the bottom of that file. The index() method from the ReSTPaths1 Class looks like this, at the top of that file:

	def index(self):
		http_method = getattr(self,cherrypy.request.method)
		return (http_method)()

If we were to insert a print cherrypy.request.method statement before the return, we would see it set to “GET”.

getattr simply says: “get me the function name in self, matching the string “GET”.
it returns a reference to self.GET(), which is set directly below the index:

	def GET(self):
		return "In GET 1.."

Notice that the index() method has a @cherrrypy.expose decorator above it. This makes the index method callable by the public. The GET method does not have it, which means we could never invoke the GET method by typing:

http://localhost:8081/GET

If you try this, you’ll get a 404 Not Found error, because it’s not visible through the CherryPy interface.

GET() has to be invoked through index(), which means GET can only be called if an HTTP GET request is issued. If we posted form data to this same URL from, say, a form entry asking people for data input, we would need to add a POST method to this ReSTPaths1() class, to receive the POST data entered in the form fields.

Now back to our example:

In this example, no part of the URL or associated resources are dynamic, in either initialization or run time. This is fine, and suits the needs of most ReSTful CRUD interfaces.

Way 2: URL paths and associated components dynamically set once, upon dispatcher init/startup:

Now let’s say we want to determine the contents of the root, and therefore the URLs and associated resources for our ReSTful interface, dynamically during initialization/startup.

We can assign the root setting by using a Python metaclass to generate classes in our CherryPy startup code, and set the root components to each generated class. This goes beyond the average needs for CRUD access, but it’s such a nice implementation that I must show it off:

import cherrypy

class MetaCRUD(type):
	@cherrypy.expose
	def index(cls):
		http_method = getattr(cls,cherrypy.request.method)
		return (http_method)()

	def GET(cls): return "In class ", cls.__name__, ', received a GET request.'

	def PUT(cls): return "In class ", cls.__name__, ', received a PUT request.'

	def POST(cls): return "In class ", cls.__name__, ', received a POST request.'

	def DELETE(cls): return "In class ", cls.__name__, ', received a DELETE request.'


baseCRUD = MetaCRUD('baseCRUD',(),{})
root = baseCRUD

dynamic_class = {}

for d in ['legacy_dbi','new_dbi','some_other_dbi']:
	dynamic_class[d] = MetaCRUD(d,(),{})
	setattr(root,d,dynamic_class[d])

cherrypy.server.socket_port=8081
cherrypy.quickstart(root)

Here we’re using a metaclass, with CherryPy exposed methods, to generate a dictionary of dynamic classes. We set the root.classname = the_new_class by using the setattr() method.

After initialization, URL components and resources are fixed in this model. But wow, the awesome power we have during initialization, in 28 lines really rocks. I wrote this in 30 minutes, and realized again why I am so head-over-heels in love with this language.

When we hit these URLs:


http://localhost:8081/


http://localhost:8081/legacy_dbi/


http://localhost:8081/new_dbi/


http://localhost:8081/some_other_dbi/

We see this output:

In class baseCRUD, received a GET request.
In class legacy_dbi, received a GET request.
In class new_dbi, received a GET request.
In class some_other_dbi, received a GET request.

Let’s issue a POST request via curl, on the command line. The response is returned:

[gloriajw@g-monster ~]$ curl http://localhost:8081/some_other_dbi/ -d ""
In class some_other_dbi, received a POST request.

This model could be used for, say, reading the contents of the Postgres template1 databases list or the mysql ‘show databases’ command, and auto-generating a ReSTful CRUD interface for each. Access of each resources can be controlled via HTTP Auth methods. This is a great solution to providing, and restricting, legacy database access for new processes through a standard interface.

Way 3: Live, ever-dynamic determination of URL and associated component:

Some ReSTful URL models may need to be ‘run-time dynamic’, especially in the case where databases are dynamically created, and the associated resources per new database could vary. There is a simple example of a dynamic URL and resource model:

import cherrypy
import pprint

class ReSTPaths:
	@cherrypy.expose
	def __init__(self):
		pass

	@cherrypy.expose
	def client(self,*args,**kwargs):
		return "Your HTTP method was %s. Your args are: %s and your kwargs are: %s\n" \
		% (cherrypy.request.method, pprint.pformat(args), pprint.pformat(kwargs))

	@cherrypy.expose
	def address(self,*args,**kwargs):
		return "Your HTTP method was %s. Your args are: %s and your kwargs are: %s\n" \
		% (cherrypy.request.method, pprint.pformat(args), pprint.pformat(kwargs))

cherrypy.quickstart(ReSTPaths())

This allows for dynamic URLs such as:

http://localhost:8080/client/address/34567

http://localhost:8080/client/address?client_id=34567

http://localhost:8080/address/client?client_id=34567

http://localhost:8080/address/client/34567

http://localhost:8080/address/anything/anything_else

The output from this code looks like this:

Your HTTP method was GET. Your args are: ('address', '34567') and your kwargs are: {}
Your HTTP method was GET. Your args are: ('address',) and your kwargs are: {'client_id': '34567'}
Your HTTP method was GET. Your args are: ('client',) and your kwargs are: {'client_id': '34567'}
Your HTTP method was GET. Your args are: ('client', '34567') and your kwargs are: {}
Your HTTP method was GET. Your args are: ('anything', 'anything_else') and your kwargs are: {}

Notice that we only have keyword args (kwargs) when we pass a named parameter, such as client_id=34567

Let’s try a POST request from curl, on the command line:

[gloriajw@g-monster ~]$ curl -d "something_else=whatever_i_want" http://localhost:8080/address/anything/anything_else
Your HTTP method was POST. Your args are: ('anything', 'anything_else') and your kwargs are: {'something_else': 'whatever_i_want'}

In this code, the sky is the limit. You can place whatever code you like in these methods, dynamically creating classes and resources as needed, letting them only persist until the result is returned. This may add some inefficiency, but in exchange offer more secure network resources.

Code is attached, Enjoy!

Gloria

http://www.devchix.com/wp-content/uploads/2009/04/restfixedargs.py

http://www.devchix.com/wp-content/uploads/2009/04/restmeta.py

http://www.devchix.com/wp-content/uploads/2009/04/restvarargs.py

Love, Software, and Squeals of Delight


ReviewsSoftwareThoughts

Dock

Software does more than crunch your numbers or take your picture: it can make you angry or bring you joy. And those are the things that we, as developers, have to tune in to if we want to make our products stand out.

Skitch is one of a handful of products I’ve used recently that remind me what makes a product successful. Utility is important, of course, but the love and emotional connection it engenders in its users is where it’s going to live or die.

Let’s start backwards, with the logo, since it’s the first thing you see. Their logo says nothing about their product’s functionality. There’s no initial, no recognizable signifier (thanks for sparing us the paintbrush), or even an abstract swoop. It’s, um, a heart.

And not just any heart, but a hot-pink, shimmering, pumping, overflowing, disco heart.

They’re not saying, “You might like us”. Or even, “As you can see by the ‘S‘, we’re Skitch”. They’re saying, “This is LOVE, baby!”. You and me!!! (How they’re managing to do that without coming across like Mr. Roper, though, is a mystery that is beyond the scope of this post.)

Now, this Love they offer, it’s not too intense. It’s not Valentines Day Red. It’s not a pushy “when are you going to commit” heart, a dreaded “we have to talk” heart, or even an “I’m complicated, but deep” kind of heart. Just hey, hearts, baby, I’m an extrovert, let’s groove on the dance floor and take some snaps!!!

I focus on this because right there in their identity they align themselves not with Software, but with Love and Play — a great gap to bridge. If the product sucked, it would be one thing. But it doesn’t. It makes bold choices and executes them well. They’re going for the whole tamale, not hiding behind industry-speak, and not afraid of a little heart and soul.

So, they have a lot to live up to. Moving beyond the logo, what does Skitch do that works and how can we learn from that?

It’s makes it easy to get started.
I haven’t taken the time to figure out all the features — in fact, I was too ADD to even watch the whole 3 minute video. But I didn’t need to. The critical 2 or 3 features are easy enough to get right away. Once someone commits, they’ll go deeper, but don’t make them wait, fiddle, or read a manual first. Make your learning curve the equivalent of 140 characters or less.

It does the things you’d want it to do.
This may sound simple, but it’s worth repeating. I wanted to take screenshots, write on them in fun fonts with arrows, then upload them to the web. Bingo. No matter how fun an imagined feature is, the trick is matching it to the intuitive use of your product. If people wouldn’t naturally want to do that thing, drop it. It doesn’t matter how slick it is.

It cuts out the middle steps.
In Skitch, you don’t have to select layers, like in Photoshop, to move items that are separate, such as text and arrows. You don’t have to explicitly save the picture on your desktop and then FTP it to the web — the app does it for you in one click. The designers have figured out your starting and ending points, then cut out all the excess steps in between. Spend time here, trimming the middle.

It makes it fun.
It understands that an application is not just about utility: you’re not just tediously trying to upload a picture to a website or share it with a friend — you’re having a moment in your life. Make that moment simple, and when you achieve that, make it fun.

It makes common actions unexpectedly pleasurable to use.
There are tons of patterns we use all the time when interacting with web and desktop applications. For instance, copy and paste. Copy and paste is great and I love doing it, but the folks at Skitch saved me a couple keystrokes by giving me a fun copy button on the image detail page. It wasn’t necessary per se, but it genuinely improved my user experience. So, don’t try to think about new things you could add: find out what the most integral interactions with your product are. Improve those.

Squeals of Delight
That’s what I did when I first used that copy button. That’s what I did when I clicked “webpost”, heard a whoosh, and saw that my screenshot was now on my very own Skitch web page. Go for the squeals: it means, this feels JUST RIGHT. If someone is squealing with delight (for Love or Software!) they are going to come back.

It’s not all paradise and apples of course.

There are confusing and frustrating interactions, just like in any product. These stand out more, ironically, because they raised the bar so high. So Skitchers, as you move forward, solve these problems for me :)

1. How do I get back to my home skitch page from a specific image page? You don’t really mean for me to click on the back button or delete the rest of the URL in the address bar after furrowing my brow looking for the obvious home link, do you?

2. Uploading. From my Skitch app window, I can’t click “webpost” right away because it first shows me “share”. Only after clicking on the “share” is “webpost” exposed. Since clicking “share” triggers a browser window populated with the Share link that steals focus, I have to tab back to Skitch to webpost. Annoying.

Overall, It was great to look at Skitch because it’s so well done. I think it’s worth taking a product apart to see why it works and how we can use those lessons in our own applications.

And finally, Full Disclosure: I have nothing to do with Skitch.

I just heart them.