Sunday, October 28, 2012

A speaking experience


TL;DR - Speaking is awesome, and JDD Kraków is the awesomest.
I sit in an orange chair at a table set with two forks and three knives. This hotel in central Warsaw has 31 stories and a lobbyful of teenagers chattering in Hebrew. I order krem grzebowy (cream of mushroom soup) and pierogi z grze... mushrooms.

This is a long way from St. Louis, MO. I'm a long way from the developer I was two years ago.

JDD brought me here to speak at a software developer conference in Kraków. JDD is a medium-size conference, about 450 attendees in three tracks. It is exceptional in hospitality. If you've ever wondered what speaking at conferences is good for, JDD is the answer.

The people barely fit into three rooms packed with chairs in the largest hotel conference center in Kraków  Yesterday when the hostess introduced my third talk, the audience clapped. This is not standard - normally clapping is only after the talk. They clapped for me, because they heard one of my earlier talks and were excited to hear me again.
I blushed and my eyes watered. "Thank you," I said. "I love Poland. I love Kraków, a beautiful city and I love the people and the vodka and the pierogi. Thank you for having me." Then I launched into Git Happens. Fifty minutes later the conference ended. People left the room better motivated and equipped to use distributed version control. Several approached me with more specific questions (I still owe some of you an email). Each thanked me for the talk. Ian, a speaker from Ireland, said I'm even more enthusiastic about git than Matthew McCollough - that's saying something!
At least two people thought I was the best speaker of the conference. I made their experiences better. I helped them find new enthusiasm for git, or Android, or thinking about code in new ways. Maciej was thrilled that I retweeted him. With such a small thing, I made his day.

This is speaking at conferences: improving the lives of developers in a whole 'nother part of the world, spreading my enthusiasm and receiving "thank you" and "I enjoyed your talk."
And there is so much more. The experience of speaking takes place mostly outside of the conference.

It started this time with a trip to Europe, which JDD arranged. Karoline picked me up and the airport and escorted me in a taxi to the hotel. At the the Galaxy Hotel in Kraków one of the elevators plays birds chirping. In the room, you have to put the key in a slot by the door or else the lights don't work.
I came in a few days early. The conference took care of all hotel, meals, tours of the city - not just transportation, but friendly escorts. Natalja (the Polish j makes a consonant y sound) rode with me in the taxi to the salt mine and helped me learn the three different ch sounds in Polish. The ć character, like at the end of cześć (hello), you have to pull your cheeks back and use your smile to get it right. Natalja is studying international relations, so she likes to practice her language skills with speakers.
I toured the salt mine with Andrew (dang, lost his last name) and Ron Broersma, two speakers at the PLNOG conference earlier in the week. Ron has been networking computers since 1976 -- before I was born, before the PC existed. Did you know that IP (Internet Protocol) was invented because computers were scarce and expensive? Ron told me the story of TCP/IP, which includes railroads and the breakup of AT&T.
We finished that story over dinner. Sławek (short for Slawomir; pronounced "Swavek") took us to the old Jewish quarter. I ate pieroszki, which is a diminutive pierogi. Sławek shared four different Polish liquors with us: a honey one, a cherry one, one made from grass that has been pissed on by a bison, and a hazelnut one.
Church inside the salt mine
At that dinner the conversation turned from networking to development, and I shared some of the inspiration for my Functional Principles talk. Not only did I converse with two deep experts in computers, but I contributed in the conversation. They were interested in what I had to say. Before speaking, before thinking and learning and organizing my thoughts about development, I could not have done that.
I met Joe Yoden, who lives a few hours' drive from me and coined the "big ball of mud" antipattern. And Rebecca Wirfs-Brock, who started the "x Driven Design" meme -- the first x was Responsibility.
From Hardy Ferentschik I learned that in Sweden there is great sailing, while in Australia they don't have enough green plants. Hardy works on Hibernate for RedHat. He described his experiences working with a team scattered across the world that incorporates the work of open-source contributions.
a tall chamber in the Salt Mine
At the conference party, every time I got near the dance floor, someone different jumped up and danced with me. That was a blast! I made their days a little better, too.
I talked with Andrzej (Andre to English speakers), already a conference organizer at 26. He mentioned being an outcast as a kid and giving up on caring what people think. I suspect this is a source of innovation in our industry.

It is snowing in Warsaw. The people on the other side of the window have umbrellas. In the mall in Kraków  there are tons of coats and tights and sweaters and boots. Coat check rooms are prominent here.

It is not all fun. It's the first time I've spoken without a close friend around to help practice, give me a hug, and tell me I could do it. I know I can do it, but I really could have used some hugs. Hours spent in my hotel room tweaking my talks because Slawomir took a risk inviting me, and I had to do well. Sightseeing and sessions skipped, alone and scared.

On the last night in Kraków, for the third speaker dinner, Sławek took us to a traditional Polish restaurant near the main market square. The first thing served: vodka. Andrzej and Pawel and Piotr claim that their generation doesn't drink vodka with every supper. But Jarek does! Jarek and I connected in this way: every time we looked at each other, vodka appeared. Jarek told me about his experiencing building an architecture team around a legacy app that had none, and the differences between teams in various parts of the world vs teams with members spread across the world. (hint: the first is better.)
On the way to the main square we passed the castle. It is huge! brick, stone, many materials, blocks and blocks of walls and windows. Kraków was not destroyed in WWII like Warsaw was, but there were many battles in earlier times.
St. Louis has never had a war.

Tired from the heavy food, a handful of us set out for a bar anyway. The underground bar reeks of history. Those walls were shaped and patched before my country was born. People peeled off, abandoning their vodka. I took care of that.
And then, a dance club! Patricja lives in Warsaw and started her own company automating optimization of source code. (She should speak at StrangeLoop.) She does not care for vodka or śledż (a brined herring that I looooved), but she does like dancing! Four of us explored an industrial dance club with many rooms, all underground. Dim, smoky, loud thumping unfamiliar music. Excellent.
Around 4 we returned to the hotel. I woke up in the bathtub sometime after sunrise. Poland and I, we got along.
Speaking is about experiences. It is about forming connections through conversations with intelligent people who also love to learn. About taking these clues home and weaving them together into the next presentation to stimulate people at the next conference. Speaking is about making people's day, and letting them make mine.

Not all conferences are like JDD. Most in the US don't even pay travel expenses for speakers. I don't know any that host the way Sławek and Justyne do. They arranged this hotel in Warsaw for me, because my flight to Amsterdam leaves at 6:20 a.m. tomorrow. The krem grzebewy is delicious.
When I was alone and in need of a hug before my presentations, that was scary. The accolades afterward make me forget. On departure, I received hugs from several new friends. Speaking is not easy, but it is rewarding.

Thank you to the JDD organizers, Sławek and Justyne and ProIdea. Thank you to the hostesses, Karoline and Natalya and the others. Thank you to all the people who listened to my talks, especially the ones who gave feedback. Thank you to the other speakers who talked to me, for their fascinating company. Thank you to everyone who helped me get here, and thank you to my friends back home who emailed and Skyped during the scary parts. Thank you to my husband, who is proud of me. Thank you to Kraków.

This is what if feels like to be alive.

Saturday, October 13, 2012

The chicken and the egg both come first

Yesterday at the Java User Group, I talked to someone with a recent Ph.D. in Computer Science who can't get a programming job. Why? He doesn't have experience. Everyone wants to hire a Java programmer with Spring and Hibernate to program in Java using Spring and Hibernate. To get experience, you need to have experience. This same chicken-or-the-egg problem shows up all over the job market.

Me, I'm lucky: I graduated in 1999 when everyone was hiring entry-level programmers. You could graduate with an English degree and get a programming job in 1999. [1]

The real way to get a good job is through word of mouth. The best jobs don't go through the recruiters who are screening everyone for experience in Spring and Hibernate. Like so many things in life, it's all about who you know. And how do you get to know people? Through people you already know! It's all about being part of the community.

Communities exist in our field at many levels. In Structure of Scientific Revolutions, Kuhn shows that small communities within each scientific specialty decide when a new paradigm is superior to an old one. They control the direction of the field and set the rules for all practitioners of their science.

Getting a job is one challenge. Getting into the community that defines the direction of the field is another.

To excel takes hard work, merit, and opportunities. If any one of these is most critical, it is opportunities. [2] How does a person become qualified for an industry-leading group? Experience. How do they get experience? Someone gives them that first opportunity.

How does a hard-working, skilled person get into a community? Someone invites them in. Work all you want, but until someone gives you a chance, you're stuck on the outside.

Me, I was lucky: someone invited me into the conference-speaker community and introduced me to people who are now my friends. I'm speaking, blogging, tweeting, and digging into technology all because one person held out a hand and said, "you could do this too."

If you are a hiring manager, look outside the official experience profile and hire someone smart.

If you are part of a community, especially an informal one, find someone with potential and hold out a hand. Invite them to your gatherings and share ideas. Look beyond the obvious candidates. Raise up more chickens, and we'll get more eggs. Everyone will eat better.


[1] My coworker Sarah did.
[2] Outliers, by Malcolm Gladwell. If you disagree and haven't read the book, please read it.

Git Rebase inside IntelliJ IDEA

Rebase is one of the most awesome commands in git. Use it to keep the local branch up to date with what's going on in trunk. A rebase a day keeps merge conflicts away!

In the form advocated here, rebase takes your branch's local changes and applies them to the most recent code in the master branch. This makes git look as if you made your changes to the latest code, instead of to older code. Everyone else's changes are incorporated into yours without an explicit merge commit.

Frequent rebasing reduces merge pain by catching conflicts early and in small quantities. Nothing can eliminate merge pain entirely. When conflicts do come up during rebase, git doesn't make it clear what is going on. To help with this, I turn to my favorite IDE, IntelliJ IDEA. Unfortunately IntelliJ doesn't make it clear either.

This post steps through rebasing a working branch to bring in the latest changes from master, inside IntelliJ. The merge-conflicts support in IntelliJ is good, but beware! It is not quite what you expect, so watch out, and read on.

Before starting the rebase:
1. Commit all your changes to the local branch. If you're in the middle of something, commit it anyway. You can tweak that commit history later.
2. Bring the central repo changes into your master branch. (Most people use "git pull.")
3. Check out your local branch.

In IntelliJ, look in the Changes view, at the Log tab, to see the status of your repository. If it looks like this, with commits on both master and your current local branch, then this post is for you:

To start the rebase within IntelliJ, go to the VCS menu; select Git and then Rebase...
In the dialog that appears, uncheck "Interactive." The interactive rebase serves a different purpose. In the "Onto" field, enter the master branch, the branch with other people's changes. Click Rebase.


If there are no conflicts, well, lucky you, you're done. It gets interesting when the "Rebase Suspended" box appears.

Conflicts! Time to resolve them. Note that "(0/0)" here has no meaning. I've seen that piece work in an interactive rebase, but not this one.


Once you click OK, nothing happens. This is confusing. Your git repo is in an intermediate, mid-rebase state, but you can't tell. The secret here is to go to the Changes view, and look at the Local tab. Now we see the files in conflict.


Caution: don't walk away
Don't leave your repo in the middle of a rebase. You'll be confused as heck when you return to it later and aren't on any branch. Either finish the rebase or admit defeat with VCS -> Git -> Abort Rebase.

To resolve the conflict, right-click on the file, choose Git, and then Resolve Conflicts. (Anybody know if there's a handy button for this?)


Now watch out! The "Files Merged with Conflicts" dialog looks familiar from my subversion days, but the column headings are deceptive. "Yours" and "Theirs" don't mean what you think they do. Click on Merge to look closer.

The Merge window appears. Look closely at the "Local Changes" side and the "Changes from Server" side - they're the opposite of what you expect. The Local Changes were made on the master branch, and the Changes from Server were made in your local branch. This is the opposite of what you would expect in a merge, even a git merge. The rebase has the changes backwards.

Technical details
This happens because of the way rebase works in git. Rebase starts from the tip of the "onto" branch, master. Then it applies the localFeatureBranch commits there - so in git's mind, we're starting from master ("Local Changes") and bringing in the localFeatureBranch commits ("Changes from Server"). In git terms, the master tip is ORIG_HEAD and the local branch is MERGE_HEAD. It would help if the column headings in IntelliJ were customized to reflect this.

Now that you know which changes are which, merge them together and then save. You might see this "File Cache Conflict" dialog pop up. The changes IntelliJ is making through git and the changes it's making internally are not quite synchronized. You must choose "Keep Memory Changes" in order to retain your merge!

Repeat this process with any other files in conflict. IntelliJ's conflict resolution automatically adds the file to the git staging area, which is necessary to continue the rebase. Once all conflicting files are merged and in the staging area, continue the rebase. VCS -> Git -> Continue Rebasing.

If that's the last conflict, then nothing happens. You don't get any sort of congratulations, you're just back to work. Flip to the Log tab in the Changes dialog, and see the nice straight line that shows your localFeatureBranch growing out of master. All changes are now incorporated. Good job!


If there was more than one commit on your local branch, then there's a good chance you'll find more conflicts. The "Rebase Suspended" dialog pops again, and you get to resolve more conflicts and Continue Rebasing again.
DON'T PANIC
If at any point you decide this rebase is a disaster, choose VCS -> Git -> Abort Rebasing. 

That's it for rebasing inside of IntelliJ, as of v11 of the IDE and the bundled Git Integration. If I had infinite time available, I'd love to write another plugin just for rebase, because it's a very important and very cryptic operation in Git.

Friday, October 12, 2012

Duck typing is like the force


Scala's type system is impressive, and yesterday one feature came in handy: converting certain classes into a common type with useful methods on it.

Say several types have a core set of characteristics, and we want to define methods based on those without modifying the original classes. In this example, various classes represent regions of a chromosome, and the common characteristics are a begin position, end position, and strand. I want to be able to ask each of these whether they contain a particular position on the chromosome.

A section of something can be efficiently represented by a case class, and methods can be added there.

case class Section (begin: Int, end: Int, moreInfo : Char) {
    def contains(position: Int) : Boolean = { … }
}

Then when I have some other class, say a chunk, that contains the information that defines a Section:
Section(chunk.begin, chunk.end, chunk.moreInfo).contains(positionOfInterest)
But this gets verbose. I want to go straight from the Chunk to the Section without pulling individual fields. I could create a custom apply method in Section's companion object:
object Section {
   def apply(Chunk chunk) : Section = Section(chunk.begin, chunk.end, chunk.moreInfo)
}
Now: 
Section(chunk).contains(positionOfInterest)
But that only works for one input class - I also want this to work for wads, hunks, etc. For a more general approach, a structural type works better:
object Section {
    type T = { 
    def begin: Int;
    def end: Ind; 
    def moreInfo: Char }

   def apply(thing : T) : Section = 
     Section(thing.begin, thing.end, thing.moreInfo)
}
This apply method will convert anything with the right properties into a Section.
Section(chunk).contains(positionOfInterest)
Section(wad).contains(positionOfInterest)

Section(hunk).contains(positionOfInterest)
It would be even more fun to make the apply method implicit and start using the contains method directly on the arbitrary areas. This doesn't work, though. Scala won't do implicit conversions into structural types. That would get ridiculous.

Duck typing is useful this way. I feel all clever for figuring out how to do this -- a common feeling among those who play with the Scala type system. However, if I have control over the source code of Chunk, Wad, and the other types I want to call contains on, the correct way to do this is with a trait:

trait Section {
   def begin: Int
   def end: Int
   def moreInfo: Char

   def contains(position: Int) : Boolean = {…}
}

Add this trait to the declaration of the classes that represent areas, and the contains method works even better. No additional code is required inside the implementing classes; they already define the abstract fields listed in the trait. Things just work.
class Chunk extends …. with Section {…}
chunk.contains(positionOfInterest)
or,
class Wad extends Section {…}
wad contains positionOfInterest
Traits are the better way to add common methods defined in terms of common fields. They give Scala more information at compile time. Now contains show up in autocompletion in the REPL or the IDE.

Therefore, use the force -- I mean, duck typing -- as a last resort. It's powerful when we can't modify class definitions, but honest, up-front static typing is better.

Monday, October 8, 2012

Why and how

Premise: Our brains learn by recognizing patterns. We see patterns everywhere and we don't notice that we are learning them. Advertisers show pictures of products next to pleasing images; we form associations.

Premise: We notice gender immediately. We can't even think about a person without first deciding "he" or "she".

Premise: Most serious programmers are men. If you question this, you don't work in the US.

Consequence:
Without intending to, we associate programming with men because our brain has silently observed this pattern. When we see a woman at a user group the brain signals, "recruiter." When we see two resumes, the one with the masculine first name signals "serious programmer." This isn't anyone's fault. Our brains just work this way. The really senior, wise programmers are the graybeards. The term reveals and reinforces the pattern.

On our side, women don't see the technical side of computer science as a career path. I see very few role models at the top - none yet in the US in the JVM space. I see many groups that are all male. The first and hardest step in getting more women into the influential groups is to get one. It never occurred to me to aim for the ranks of technical leadership, partly because every speaker on the NFJS tour is male. Those were the only conferences I had attended. While I love public speaking, I didn't picture myself in front of a group of developers - until someone asked me. Until someone offered me the opportunity, and then I jumped at it, and excelled. There are hundreds or thousands of other women in IT who are quietly doing their jobs, who never thought seriously about leading as a technologist, who would flourish if approached with opportunity.

Steps to counteract each of these causal factors:
Recognise that it happens and try to compensate consciously. The least biased people are the ones who recognize their bias. When possible, look at resumes without a name at the top. When orchestras started blind auditions, they magically went from male-dominated to evenly divided.

When you're doing those blind selections, it helps to know that 'they' is grammatically correct in the singular. Try to use it as a gender-neutral pronoun, and realize how deeply embedded gender is in the American psyche.

Change the patterns we (and future people) see by getting more women into programming, and more women in prominent positions in programming. Long term, the bias will go away when the pattern goes away. Bring women to the forefront of the field. If you're selecting a leader and the best woman you can find is not as qualified as the best man you can find, (1) check your numbers to make sure unintentional bias isn't working against her, and (2) hire her anyway. She is smart and she will rise to the occasion. She is not as experienced because women haven't been given these opportunities in the past. So give it to her. Next round, she will be the most qualified.

Am I advocating affirmative action in hiring? No, I'm advocating blind hiring as much as is feasible. This has worked for conferences that do blind session selection and seek out submissions from women. However, I am advocating deliberate bias in favor of a woman in promotions, committee selection, writing and speaking solicitation, all technical leadership positions. The small biases have multiplied until there are almost no women in the highest technical levels of the field. This imbalance is both most egregious and most harmful. It impacts impressions of women considering entering the field, of women in the field picturing their future, of teachers, of hiring managers, and of current leaders selecting and encouraging peers. Participation in leadership is determined by fewer individuals, and if these individuals take deliberate action to bring women in, the impact these women have and the impressions they create will take root in brains throughout our industry.
This article is a great breakdown of the bias that exists: http://www.cnn.com/2012/10/01/opinion/urry-women-science/index.html?c=&page=3

Sniffing traffic between my app and local CouchDB

This turns out to be a lot harder than watching browser traffic.
Forgive the crudity of this post; I'm on a tablet. Gotta get this info out before I forget, because this problem was a sticky one. Couch returned a 400 Bad Request with the error message "invalid json" and I needed to see the json it was receiving.
To watch the HTTP traffic on my local machine (a Mac) moving between my application and CouchDB on port 5984:
  • download and install Wireshark
  • capture traffic on the loopback interface, lo0
  • set up a capture filter for only this port: tcp port 5984 (not entirely sure I got this working, and the capture filter is not strictly necessary)
  • enabled http packet reconstruction on this port: edit, preferences, protocols, http, add 5984 to the lost of tcp ports (this is the critical secret step of working!)
  • ran my test that failed, to cause the traffic I am trying to capture 
  • entered a display filter: http.response.code == 400
  • found the 400 response, clicked on it, then cleared the display filter
  • now I can look a few rows up the list to see the POST that triggered the error. The body is included in the breakdown. (Or would be if it had one. In my case the post has no body; no wonder Couch complained.)

Useful tips:
  • change the coloring rules (the pretty button at the top) to move the "Checksum Errors" rule down to the bottom of the list (this rule is triggered by all of these local packets because of checksum offloading). Then I created a coloring rule to turn http.response.code == 400 an obnoxious color. This made it easier to see what was going on.
  • In this X11 window on a Mac, the command button doesn't behave normally. Use Ctrl instead.