Pat Maddox, B.D.D.M.F.

RSpec my authority! I just smashed a bug

Some Resources for People Who Want to Learn Smalltalk

If you want to learn Smalltalk, you can get started easily. First head over to Learn Smalltalk with ProfStef where you can learn Smalltalk syntax in about five minutes using Amber Smalltalk, a Smalltalk that runs in your browser via Javascript.

I’ve had a lot of fun using Amber and find that it makes me super productive when writing Javascript applications. It’s young though, and has quirks, and the environment lacks some flexibility that more mature implementations have. If you want the full Smalltalk experience, you’ll want to check out Pharo Open Source Smalltalk. Click on the big “Download Pharo” button to get a one-click package that includes a Pharo image and a VM for your platform. The image contains everything you need to write and explore Smalltalk applications – code browsers, refactoring tools, a test runner, object inspectors, workspaces for running snippets of code, version control, and more.

When you start exploring the image you’ll find lots and lots and lots of Smalltalk. Unlike other programming languages and environments you might be used to, Pharo doesn’t make a strong distinction between your code and platform code. Everything lives and runs under the same image, and you have access to all of the source code. If you want to understand how the automated extract method refactoring tool works, you can pull up the RBExtractMethodRefactoring class to see the exact steps it takes to perform the refactoring. If you didn’t know that extract method functionality lives in the RBExtractMethodRefactoring class (as I didn’t), you can simply inspect the menu item and find out which smalltalk method gets triggered when you select that menu item. Pretty neat.

You can learn a ton from simply digging into Pharo’s guts. It has a lot of guts though, and you probably have never used a system like Pharo before. The following links should help you make sense of it:

  • Pharo by Example - free book that you can read online or download as PDF. This was my primary resource for learning Pharo
  • Pharo - the collaborActive book: Home - another great book, entirely online (I think), and probably more up to date than PBE
  • Dynamic Web Development with Seaside - an introductory book to Seaside, the continuations-based web framework in Pharo. Also probably a bit out of date, but great for learning Seaside
  • Pharocasts - a set of screencasts that goes into some of Pharo’s interesting nooks and crannies
  • Stéphane Ducasse :: Free Online Books - a list of free Smalltalk books for download. Many of them are old. I’ve only read a few of them. Definitely worth looking into.

You can find all of these links via the Pharo home page, but I figured people would find it useful to have everything on one page. I’ll update this post as I think about and discover new resources for learning Smalltalk.

Backbone.js Testing Pattern - Describe a View’s First Render

While testing my backbone.js views, I’ve come up with a few conventions to keep my tests neatly organized. The first is to have a single describe block to specify what the view looks like when it first renders. This tests the view’s rendering logic and establishes the foundation for the rest of my examples. Here’s a brief example. I have a view which renders a person’s name and adds a CSS class if the person is a minor. Pretty simple. There are three things I’m interested in when testing the first render:

  • show the name
  • no CSS class if person is over 18
  • special CSS class if person is under 18

Here’s the view spec:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
describe PersonView, ->
  describe "first render", ->
    beforeEach ->
      @model = new Person(name: 'Joe')
      @view = new PersonView(model: @model)

    it "shows the name in an h2", ->
      expect($(@view.render().el).find('h2').text()).toEqual('Joe')

    it "does not add the 'minor' class to the h2 if person is not a minor", ->
      @model.set age: 18
      expect($(@view.render().el).find('h2').hasClass('minor')).toBe(false)

    it "adds the 'minor' class to the h2 if person is a minor", ->
      @model.set age: 17
      expect($(@view.render().el).find('h2').hasClass('minor')).toBe(true)

And now the view that makes this work:

1
2
3
4
5
6
7
8
class window.PersonView extends Backbone.View
  initialize: ->
    @template = _.template($('person-view-template').html())

  render: ->
    $(@el).html(@template(model: @model))
    $(@el).find('h2').addClass('minor') if @model.isMinor()
    this

It uses this super simple template:

1
2
3
4
5
<script type="text/template" id="person-template">
  <div class="person">
    <h2> {{ model.name() }} </h2>
  </div>
</script>

If the view logic is complex I may separate the conditions into separate describe blocks, like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
describe PersonView, ->
  describe "first render", ->
    beforeEach ->
      @model = new Person(name: 'Joe')
      @view = new PersonView(model: @model)

    describe "person is not a minor", ->
      beforeEach ->
        @model.set age: 18

      it "shows the name in an h2", ->
        expect($(@view.render().el).find('h2').text()).toEqual('Joe')

      it "does not add the 'minor' class to the h2", ->
        expect($(@view.render().el).find('h2').hasClass('minor')).toBe(false)

    describe "person is a minor", ->
      beforeEach ->
        @model.set age: 17

      it "shows the name in an h2", ->
        expect($(@view.render().el).find('h2').text()).toEqual('Joe')

      it "adds the 'minor' class to the h2", ->
        expect($(@view.render().el).find('h2').hasClass('minor')).toBe(true)

With these tests in place, I can start testing the events. Details on that will be in a future post.

Join the discussion on Google+

The UX Problem That Sites Leave Unsolved

Most sites give you basic account management. GitHub’s organizations allow multiple people to administer an account and manage projects within it. When nobody pays the bills, GitHub lets you know. They put up this big banner alerting all project admins that the private repositories are frozen until you update the credit card.

Fair enough. I’m not going to solve this billing problem though. The account belongs to someone I worked with a while back who added me to the repository. If they want to address it, they will. In the mean time, I would like to get rid of that banner. After clicking around I found myself on the owners team page where I can add and remove owners.

The page gives me all the controls I could ask for…except one. I can’t remove myself from the owners team! I can kick out anyone else, or add anyone else, but I can’t walk away. I have to ask someone else to kick me out, whether that’s someone else on the team or GitHub support.

Fortunately GitHub’s design is nice and all it takes is one little tweak:

Too subtle?

I’m not really picking on GitHub here. I imagine they will address this or have a good reason not to. I’m simply using it as one real-world example of an important interaction that many UX designers skip over.

Here’s one from Google Analytics. Someone else created and added me to this mystery account three years ago, and as far as I know no longer checks his email for that account.

This case is a bit different. I can modify accounts that I’ve created, and I can view stats for an account that someone else shared with me, but I can’ t remove the account from my list.

Just something to keep in mind for those of you developing group functionality in your product. If someone can join or be added to a group, ensure that they have the power to leave, too.

Join the discussion on Google+

The Hidden Agile Value: Respect

Reading the agile manifesto, you won’t come across the word “respect,” but when I read it it’s clear to me that respect is an underlying theme. This dawned on me while having a conversation with my brother’s girlfriend, Cortni. Cornti is a dental hygienist who practices at a private dental office. Her office manages all of the patients’ dental records via old-school paper files. A few months ago, Cortni asked me what it would take to build software to replace the office’s existing paper system. She promised to bring me some example records to give me an idea of what she needed to enter into a patient’s file on a day-to-day basis. We spent about an hour talking about her interactions with her patients, the information she recorded, the frustrations she had with her existing system, and her vision of a software-based system that would solve her problems. At the end of it I must admit I was terrified for my own dental health, having learned of the whole slew of messy, painful dental problems a hygienist looks for and addresses. During that conversation, I learned a lot about how a dental office works, but I was also made painfully aware of just how much I don’t know about that profession.

We went to lunch and I briefly told her a bit about agile software development, although I never used the term agile. Our convo about agile went like this:

Me: So to overgeneralize, there are two basic approaches to building software. The first is where you and I sit down and talk about everything that I would possibly need to build, and then I go off and build it all, and show it to you when I’m done. In the second way, I’d build a tiny piece and show it to you, and then figure out what’s right or wrong about it, and keep building little pieces, getting feedback from you along the way.

Cortni: Hrm…I think we should do it the second way. I don’t think the first way would work very well.

Now to give you a bit more background on Cortni, she’s not what you would call an Agile champion. In fact, she’s never been involved in any sort of software project, or even in a company that builds software. She grew up on a horse farm in Colorado, roughly 15 minutes away from the nearest town of 1,000 people, and went to dental hygienist school because she “heard they get paid well and make their own hours.” That’s why I found it so amusing that she immediately and intuitively felt that an agile approach to software development might work, whereas a BDUF approach definitely wouldn’t. Yet that should come as no surprise. She spent three years in school just to get started in her profession. How gauche would it be of me to think that I can write software for her after one conversation, and get it right? How many conversations would we need to have before I could get it right? I don’t think it matters. There’s no way that I can do my job unless I get regular feedback from her on how I’m doing.

Whenever we try to build software, we have to be respectful of all people involved. The first point of the agile manifesto is that software creation is a human act – performed by imperfect beings in order to solve problems for other imperfect beings. We can respect this first at the team level. Software makers should be held in higher regard than a process you found in a book or learned in a workshop. Process can be instrumental in getting software out the door and enabling a team to continually improve itself and its product, but the moment you honor the process element over the human element, you’ve missed the point and will only cause your organization harm in the long run.

Respect should extend beyond the software team to the customers and users (which are sometimes a part of the software team, sometimes not, and are often ill-defined, mis-construed, or simply unknown). When developing software for a professional industry like dentistry, it should be obvious that practitioners are highly skilled and that your understanding of their work will always pale in comparison to theirs, even though you can develop sufficient enough understaning to build useful software for them. That’s why we call them “domain experts,” and their insight and feedback are critical to the success of a software project of this sort.

Another thing to consider is that not all software is built for skilled professionals. A lot of it is built for internal use by massive organizations whose employees have no choice but to use it. Without addressing the issue of how humane or inhumane it is to force software on a large group of people, it’s important that we as developers understand that we are partially responsible for the quality of worklife experience that these people have on a regular basis. It’s difficult for me to express this without sounding like I’m preaching, but basically we should just try to be aware that some of the software we build will be used by people who have no choice but to use it, other than giving up their jobs.

I have a lot more to say about this subject, but I think this is enough for now. If this resonated with you at all, I would like you to keep the principle of respect at the forefront of your mind today.

Join the discussion on Google+

How a Coding Obsession Killed My Startup

When I was 20 years old, I built a web site that earned over $2500/mo and required about three hours a week of support and maintenance. Damn good money for a kid whose rent was $300/mo. I made two huge mistakes that ended up costing me that creampuff income stream.

I only did what I knew, instead of learning something new

I didn’t even set out to build a business at first. All I did was write a little program to help me get better at poker. A friend of mine suggested that I turn it into a web site for other people to use, so I did. It took about three weeks of programming on my part, and I paid $200 for custom images to use.

At first it was great. I had a bit of a reputation on an internet poker forum, so when I launched the product I quickly received a lot of signups. After a few months, the signups started slowing down. So I did the only thing that I thought would bring in more signups - I lowered the price. All that did was cause most of my existing customers to cancel their plan, and not everyone signed up again at the lower rate.

If I could do it over again, I would have doubled the price for new customers. That way I would make just as much money with half of the signups! More importantly, it would create a sense of urgency for customers. I would have put out an announcement saying that the price would go up in a week, which I suspect would drive some new customers who want to get in at the low rate. And later on, customers would see that the price was increasing over time, so they’d know that they should sign up quick otherwise it might go up again. Lastly, my existing customers would be more likely to stick around, knowing that if they bailed they would never be able to get that low price again.

I sold it

This one’s easy. If you sell a recurring revenue generator for a pile of cash, you end up with a pile of cash and no recurring revenue. I could have bought another revenue generating product, or lived off the cash while I built something else, but instead I bought a fancy car. I was pretty smart for a 20 year-old, but obviously not *that* smart.

Why’d I sell it? Because I wanted a fancy car ;) But mostly because I didn’t know how to build a business, and I didn’t even really want to. I just wanted to code. So instead of learning how to build a business, I sold it off to someone else who would.

It pains me a bit to look back on this and think what it might have become had I stuck with it. But there’s no way to change it now. The good news is, today I’m just as interested in the business side of things as I am the coding, and I learned a lot from that first experience. Now I’ve got the motivation to stick with it and to learn how to grow a business. And next time I won’t be quite so willing to give up something that makes money while I sleep.

Agile 2011 Trip Report

I had the good fortune to attend Agile 2011 in Salt Lake City, where I got to help Liz Keogh run her deliberate discovery workshop. She is brilliant and had a few evil tricks up her sleeve for the workshop, and I think the attendees came away from it excited to dig deeper. I know I’m going to be experimenting more and more with deliberate discovery in the coming months.

The rest of the conference was pretty great. AgileConf is a weird one for me because it’s so damn big. It’s an industry conference, not a community conference. The exhibit hall is insane (largely due to the sheer amount of shitty-looking project management software on offer). But the catered lunches were delicious (the Grand America Hotel in SLC has amaaaaazing bread pudding), and people that woke up early enough told me that the breakfasts were too.

There were a lot of great sessions, but my favorite had to be Elizabeth Hendrickson’s tutorial workshop on Exploratory Testing. I walked in to find people hunched over electronic Scrabble games, and Elisabeth had written a test charter to guide people on how to explore them. I didn’t write it down but it was something like “Explore electronic scrabble with the stuff in the box to discover how it works.” In the next round we learned to be more systematic in what to look for, like how to identify variables in the system under test. We didn’t get to do the third round because we spent a good amount of time in conversation between rounds. Elisabeth is extremely knowledgeable and was able to handle any question that people threw at her, and I also love that she invites other people from the audience to answer. She’s great at imparting the information, but also amazing at turning it into a comfortable conversation rather than it feeling like a formal classroom setting.

I also enjoyed @hackerchick’s talk on Lean Startup and Agile. If you’ve read any of the books or articles on Lean Startup, you probably knew most of what she was talking about. But she covered the gamut for people who aren’t all that familiar, and brought stories and excitement to the table to boot.

As always, the best part of the conference was meeting people. I got to hang out with my ADDcasts partner-in-crime, Dave Brady, and we recorded an episode with Michael Feathers. We also kicked back in high-back chairs and pair programming Smalltalk on a 12-foot projector. Good times. I got to meet Tim Ottinger who told me about his experiences watching the internet unfold before his eyes. It was also great fun meeting ADDcasts listeners like Colin Jones and David Adsit. And of course there was that time when I sat down next to Gary Bernhardt for 10 seconds and got up to grab food and look for Gary Bernhardt.

AgileConf is huge, which brings a bunch of lame stuff but also draws a huge number of super awesome people in. I’m looking forward to next year, and I’ll definitely track down folks that I didn’t manage to meet this year.

Help Me Help You

I want to create an information product based on my programming expertise. I don’t know yet what the topic(s) will be, or if it’ll come via articles or video or some combination, but I know it will include lots and lots of code. I would appreciate it if you would take a few minutes to respond to this four-question survey I made up, to get a better feel for what people would find interesting and valuable.

A Little Bit of CoffeeScript

Alright so I wrote my first program in CoffeeScript. It’s my first pass at a blackjack simulator. My thoughts:

  • Syntax is quick and easy to learn, and fun to use.
  • I love the function definition syntax. Love love love.
  • Same goes for re-opening classes.
  • Scoping can be tricky when passing functions around, but it allows for a lot of power.
  • For loops are ugly
  • I need to learn how to do operator overloading
  • JavaScript is missing a lot of stuff. Need to figure out the ActiveSupport equivalent for JS.

All told it only took me a couple hours to skim through the PragProg CoffeeScript book and hack this up. It went fast and I was pleased with how easily I was able to refactor the code as I built it up. Next I’m going to mess around with adding browser-side features, as well as running it in Node. And I’m going to figure out how to test it.

Interested in CoffeeScript

I just skimmed through the Pragmatic Programmers CoffeeScript book. It looks like a great introduction to the language that covers a lot of ground and does so in enough depth to really get you going. I guess you can do that with such a concise languagee.

Off the top of my head, things that make CoffeeScript attractive to me:

  • REPL
  • clear syntax
  • based on “the good parts”
  • modules
  • inheritance model
  • clean function definitions
  • jQuery integration
  • Node.js & websockets
  • It’s in Rails by default
  • A lot of deployment options, including Rack

Now I just need to start messing with the language and writing some programs with it.

One Doctor’s Model for Continuing Education

A friend of mine told me that to be a professional programmer, you must dedicate at least 20 hours each week to professional development. That’s what Uncle Bob claims in his latest book, The Clean Coder, pointing to surgeons as an example of how to behave professionally.

The 20 hours figure intrigued me. My dad is an ENT surgeon, and he’s managed to keep up for 26 years in a field where “technology turns everything upside down about every two years.” He did the first half of his residency before endoscopes were in wide use, which required him to peel back the scalp and skin around the eyes in order to drill a hole into a patient’s sinus. Later, endoscopes gave him access to more parts of the body, while causing much less damage to the patient. Nowadays he uses the Fusion Navigator, which he describes as “a GPS for the body.” Impressively, he’s kept up with changing medical technology in the face of distractions such as living in a decompression chamber for a week as a part of his underwater medicine training; setting up hospitals in Thai jungles; and overseeing the medical support infrastructure for 15,000 Marines deployed to Iraq.

I asked him how he’s done it. What follows is what he told me. Of course, this is just one doctor, but I think my dad is an interesting data point for those developing a personal model for continuing education.

Observe other people at work

Dad stressed that this is the most important part of his multi-pronged approach to continuing education as a surgeon. He regularly sits in on other surgeries, observing the team’s preparation and procedure. He inevitably learns new techniques, new ways of looking at surgical problems, and how teams work together to pull off a surgery.

Attend at least one professional conference every year

Conferences create a high density population of surgeons to share ideas, and the planned presentations provide a structured way to learn about the latest happenings in the medical world.

Read high-quality material for at least 15 minutes each day

Dad reads for at least 15 minutes, every single day. When I questioned the possible depth and breadth of his reading, he said that he wasn’t reading to learn something in particular. He simply cultivates the habit of reading high quality medical information. He has a library full of textbooks and journals that he has “given up on the hope of reading everything in here…that’s just impossible.” So every day he sits down, grabs something from his library, and reads for at least 15 minutes. He puts it away when he’s done, and the next day reads something different.

Research to prepare for individual projects

While Dad hasn’t read everything in his library, he is familiar with what he can find in there, and knows where to look for specific information. So when he is assigned a surgery case, he reads the case information and then uses it to inform his research through his library. He digs up articles and reference materials that will be relevant to his case, along with materials from previous cases.

Giternal Updated to 1.1 - With an Important Bug Fix

I just released an update to giternal that includes an important fix for all users.

0.1.0 has a nasty bug that corrupts a checked out external’s .git repository. This happens because giternal sorts the files in .git before piping them to tar, in order to minimize repo bloat. Unfortunately, tar doesn’t seem to like that, and so when unfreezing the repository it loses many of the files in .git/objects. Instant repository corruption.

What you can do

The best thing to do is probably to wipe your external dir and do a giternal update after upgrading to 1.1. This will check out a fresh copy of the dependency, along with its uncorrupted git repo.

I don’t actually think there’s anything else you can do. Sorry :(

Pair Programming Session: Word Chain Kata

In this pairing session, I work with Mike and Isel to solve the Word Chain kata on the PragProg code kata site. We use RSpec to drive the implementation.

The video is 80 minutes long.

A New Way to Read

Back in The digital reading revolution: How I like to read books, DRMed content, and the future of publishing, I outlined how I approach reading and taking notes on books (aka “studying”). I also talked about ways in which I’d like to improve my reading process. Last night I decided to take a step in that direction.

To recap, I read both analog and digital books. I prefer reading on Kindle. I buy directly from the publisher when I can, because they usually offer a PDF download bundle. When I can’t find a book in kindle format, I buy the paper copy.

Whether I’m reading on my kindle or riffling through pages, I usually read a book more than once. First I’ll read through it quickly, without stopping, even if I don’t understand parts. I bookmark those as difficult sections and move on. I don’t make many notes at this point – just a few highlights here and there to indentify the author’s assertions and supporting facts and anecdotes.

After a quick first pass, I flip back through the book and take a look at my notes. These clues help me understand the book’s important points. I reconstruct the author’s arguments by stitching together the highlighted parts. I can tell the solid arguments from the flimsy ones at a glance. The Kindle makes this sort of note-rearranging a breeze because I can import the highlights into my computer [1].

I don’t always take great notes. A lot of the time, I don’t care enough to develop a complete understanding of that particular book at that particular moment. It’s good enough to mentally index the key themes and structure of the book, and let my computer do the boring task of remembering the actual words. Then I’ve got more energy to do the fun part, the part that only I can do: unlocking the author’s secrets when the time is right.

This works great for digital books, but analog requires more work. I often have vague notions of an idea or fact that I remember reading, but can’t remember which book it came from. Sadly, I can’t google my book shelves [2]. Until now.

I’ve got a fancy Scansnap S1500M that I use to scan documents into DEVONthink. DEVONthink OCRs the documents and then proposes possible filing locations. I’d like to use DT’s powerful search on my book shelf. Yesterday I took a couple of old books to Office Depot and had them slice off the bindings. Then I scanned the books for DT to archive. I’ll save the details for another post, but the bottom line is that for $2.50 at Office Depot & 15 minutes baby-sitting the scanner, I can take any book from my bookshelf and have all of its contents instantly searchable on my laptop.

Slicing a book in order to scan it felt weird at first, but it felt great to toss the pages into the recycling bin after scanning. Books (computer books especially) are heavy and a pain to move and take up space in my house. My entire library will fit on my laptop! I can load books onto my kindle or iPad for extra portability. If I want to go old school, I can print out the pages I want to read and fold them into my back pocket. I did the same thing with a few brand new books. After scanning the pages, I stapled the chapters separately. They look and feel like digests.

I’m pretty excited about this new approach. I can highlight the paper copy more aggressively and dispose of it when I’m done. My computer holds onto the master copy and makes it searchable for me. I have some ideas of how this approach could change my reading habits, but for now I’m going to just run with it and see what happens.

——–

[1] On the flip side, transcribing notes by hand adds sensory experience which can improve your ability to recall information.

[2] Google Books has its shortcomings. It can’t constrain its search to my bookshelf. Deep study is difficult due to missing pages.

A Website Experiment

I want to do an experiment. I want to change the focus of my website. patmaddox.com has always been “just a blog.” I’ve used a bunch of different systems over the years - it started off as a Typo blog, and I had brief stints with Mephisto, Radiant, Wordpress, and Jekyll. At the moment it is running a hand-made Seaside app, which I built partly as an exercise in deploying Seaside apps.

I don’t think I need the “power” of any sort of dynamic blogging engine, and I certainly don’t need all of Seaside’s power. What I need is something that will let me capture, develop, and publish my ideas. So I’m going to try something a bit different. I’m going to use a site generator rather than a dynamic blogging engine. I’ll use it to publish a blog, but I want my site to also host more structured content. Life happens chronologically, but I can make my information more meaningful and useful if I spend a bit of time organizing it and keeping it up to date.

My plan is to begin creating skeleton pages for the site. These will be sparse pages that contain some useful bit of information – tools I use, sites I like, random ideas I have, etc. Over time, I’ll build up the content on these pages, and create new pages and link to them.

I’m not going to say what tool I’m using just yet. Maybe you can figure it out from the generated HTML.

How to Hire Programmers

  1. Filter out candidates who don’t have a github / blog / portfolio
  2. Pair with remaining candidates

You learn a lot from pairing with someone.