You are viewing shannonwells

On managing your ego


Our Rails Lead quit today. I'm not surprised at all; when he first came on board in January of this year, after working with him a few days, I gave him 6 months, so he lasted about 4 months longer than I predicted. Now this guy is very, very knowledgeable, and he's contributed a lot of that expertise for good, but because of his personality, I'd say he detracted from that contribution by about 30%.

He's almost two people rolled into one, because he's totally unaware of this: he's egotistical and can be remarkably aggressive. He's also a decent guy with a good heart, but he places a very high premium on himself, his abilities and knowledge, and what he wants. If I knew him socially only, I'd probably be friends with him, invite him to my parties and whatnot, but working with him is a different story.

The first thing I realized was he's unhappy if he's not in charge AND in control of things. He immediately saw me as a threat (unconsciously of course), and began to detract as often as possible from practically anything I had to say. His favorite way of doing this is to point out how what you just said isn't as important as what he's saying ("Well, that doesn't concern me as much as.." "I don't think that's as big of an issue as..."). Since he so dominated a discussion with irritating tactics such as constant uptalking, refusing to pause for anyone else's input and talking over people, the only things left to say were often minor points. So there was a lot of alpha dog type behavior where he clearly needed to establish his place at the top of the hierarchy. He is also dismissive and cuts people off when they're talking. He really doesn't like it when people take personal initiative on something without running it by him first. He doesn't like it when people (i.e. the CTO) override his advice. At the same time, I blame the CTO for letting him get away with this behavior.

Now, despite my personal annoyance with his tactics, I realized and accepted that he had more and more relevant experience in the technologies we were using, so when it made sense, I deferred to his expertise, and occasionally I would carefully say something. At the same time, his behavior toward me made me extremely reluctant to seek his input, and I avoided it unless I felt like I had to.

That's the meat of this problem: when you are unpleasant to work with, people avoid working with you. In extremes it can render your contribution as a net negative. You might remember the to-do around the "No Asshole Rule" at Stanford and Bob Sutton's book about it back in 2004. (See, "Why I Wrote the No Asshole Rule".) There is solid research backing up how unproductive it is to have an asshole coworker. I now realize you don't even have to be a complete asshole; you can actually be frequently enjoyable as a person and sometimes an asshole. There were times where this guy REALLY ticked me off. There are a few unsent draft e-mails about it in my Drafts box.

In of the most recent, egregious (and characteristic) incidents, our CEO asked a question, and nobody was answering so I turned around to answer it. This guy listened for a second, jumped to a wrong conclusion about what I was saying, completely cut me off in a loud voice and answered the question himself.

The effect of bringing this guy on board was that I felt shut down; I felt like my input was no longer valued. I am egalitarian to a fault (literally), and very much of a team player. I cannot stand getting into these status competitions, and so I generally give up. I wasn't the only one. This guy effectively shut down every other engineer's input but the CTO's, and he frequently tried to shut him down too.

Once he'd established well enough, in his mind, that he was top dog, his stress-aggression subsided, but not entirely. Maybe it was just me, but whenever he was out, the mood in the room was lighter and more cooperative. Gradually, I noticed that his complaining increased, and he just never really seemed to care all that much about working for our company. Team player is definitely not a term that applied to him.

Recently he got into it with our CTO in a meeting, which I later found out wasn't the first time; it was just the first time we really saw it. I figured for sure he'd go straight out and start job-hunting after that, and looks like I was right. This situation is very similar to when I was at Apple on the iPod team. I started out in QA and it was just me and this guy Mike. Mike got into it with Tony, over something that Mike screwed up on big time. This confrontation pissed Mike off and he found another job, working for his previous company. When he told me he was job hunting, I told him I thought he would regret it, and that he should stick it out. I thought he was an idiot; I thought this was a good stable position at a good company, and we stood to do very well. Similarly, I think this guy is an idiot. This is an even better opportunity for success and to potentially do very well for people who need help.

I guess I have the last laugh, because I'm still here and he's not.

As our CTO pointed out, it's not just about what you know. The rest of us, in part due to this guy, know a lot more about Rails, Ruby, and finance applications than we did over a year ago. That's because we're all smart, and smart people can always learn more facts and technologies. What is a lot harder to learn is how to manage your ego, how to be a team player, how to lead, and the shallowly paradoxical value in being personally invested in your company's success in order to ensure your own success. That is what team playing gets you.

If you see yourself being described here (or perhaps even if you don't), the salient points here are, no matter how "good" you think you are:


  • You're not necessarily the smartest one in the room; even if you are, you're probably so close that it doesn't matter.

  • Intelligence, for the tech industry, is a requirement, so everyone has that one. You need to be more than that.

  • Knowledge without wisdom is nearly useless. Wisdom is something you only get with experience. Remember that when you're talking to the oldies.

  • A company's success depends on the combined and coordinated efforts of many people, of whom you are only one, and anyone can be substituted. I mean that; literally anyone, and if a company goes down because one person is gone, it never deserved to go anywhere. If you're too much of a PITA, even if you aren't asked to leave, you'll definitely never be invited to work with them at a different company. There are many former coworkers on my personal blacklist, who I will aggressively advise against their being hired at a company where I'm working, should they come up as a candidate.

  • Be nice. I don't mean suck up, I don't mean be phony, I don't mean be a doormat. I mean: don't yell at people, don't belittle or be insulting, do solicit their feedback, do let them talk. Be polite and pleasant. Studies show that nice, less competent people are more effective than assholes because everybody wants to help them and work with them. Just think how far a nice, extremely competent smart person will go. (See "Competent Jerks, Lovable Fools, and the Formation of Social Networks")

  • Company success is your success.** Help make it happen. Try "is there anything I can do to help?" on for size.



** If it's not, that is, if you're not benefiting from company (or organization) success, time to leave; it's probably being run by assholes.

We have all of our repositories on @GitHub and we initially tried a pure Git flow model, however, that was too clunky and involved for our needs. We have recently switched to a process where we use git flow to create a feature branch, push it and when we're ready to merge with develop, we create a pull request. Once merged we do releases directly from develop (the nature of our web application allows this). Pull requests are not merged until at least one person gives it the go-ahead. We've been using our own judgment on this; for simple changes one other person's okay is enough, but for more complicated ones we generally wait for more team members to comment.

What we've found is that this results in cleaner, less buggy code once merged to develop. Bugs, misunderstandings and inefficiencies are usually caught very early on, because this process not only requires code review, but makes it easy. Github's pull request UX is great; discussion and diffs are simply tabs in the pull request page. Comments have some limited markup, and can include screenshots, which is awesome for illustrating any issues with the pull request. If the merge has to be done by hand it's shown right there and you can do your rebase and push again.

Additionally, I'm very satisified with GitHub's @TravisCI integration. The pull request shows right away whether the tests have all passed and it's "safe" to merge.

Here's a gist of some of the Bash functions and aliases I use to make things even easier:
https://gist.github.com/shannonwells/6719247

This has bitten me twice now so I'm posting it here.

We had a jasmine test failure that failed only on Firefox and not in Chrome. We had significantly changed our forms UX so it was not surprising that weird failures would occur.

It turns out that, jQuery("select")[0].value returns the value of the selected option in Chrome, but only the value of the first option in Firefox. I had overlooked the selector we were using and that is how I discovered this. Note this is not about jQuery behavior but JavaScript.

To observe this failure, construct a jasmine test that chooses an option from a select tag like the following gist:

(I'm not really sure what those numbers are about, but if you click on the filename link it will show you the gist and it will look nicer.)

Now open console (Chrome) and Firebug (Firefox), and run the test in each.
In Chrome, the outputs will both be "baz."
In Firefox, the outputs will be "foo" and "baz."

In short, you shouldn't be asking for the value of a select anyway; you should always get the value out of the selected option.

We did not properly migrate our UI changes in our specs and so I was fooled into thinking the jasmine tests were passing (because I was running them under Chrome), when they would fail on our CI (which runs jasmine under Firefox). It happened again, for similar reasons in our Backbone form View, too.

Heroku boot-crash loop


Once again, haven't really seen this posted elsewhere, but if you deploy to heroku something that you know works (especially on staging), and there are no other indicators as to why it is happening, a heroku app stuck in a boot-crash loop may be fixed by:

heroku restart


Yes, that's it. If it's stuck in a boot-crash loop, try restarting. Go figure.

My javascript-goes-at-the-end trick


I don't think I've ever seen this solution anywhere else (perhaps because it's obvious), but it seems to work well for us. You want to speed up your page loading by putting all the javascript at the end, no? However you don't always know ahead of time, in Rails, when you need to call certain functions, etc. So this is what we do:

In my partial template that is included in every layout, views/shared/_footer.html.haml, we have the following, last:
    = yield :extra_javascript


In any template where we want to call some specific function in my numerous javascripts, we do as in the following example:
- content_for :extra_javascript do
:javascript
Dudada.Users.initializeEvents();
Dudada.ProductGroups.initializeEvents();
Dudada.Reviews.initializeForms();
//(etc.)

Gotchas:
===> Be sure to restrict this tactic to main page templates, and avoid putting it in partial templates unless you absolutely have to, where you know for a fact it won't be included multiple times on the page.

===> Also note that this code will NEVER be executed in an AJAX response, because it always comes with the footer, i.e. only with a full page load.

NB: this post triggered a code review where I realized we had way too much of this in partial templates.

For Rails coders


I just wrote the_missing_spec this afternoon. It's a really, really basic missing RSpec test finder and generator Rakefile, hosted on Github. Posted here because I couldn't find something similar (okay, I only skimmed the first handful of links on a couple of web searches).

Tags:

RSpec testing nested routes


Never fully explained in Stack Overflow or adequately by RSpec or Rails documentation, aside from "index."

From routes.rb, noting that announcements are not routed outside of this block:
  resources :users,:product_groups do
    resources :announcements
  end


The syntactically correct way to test nested routes is this:
For checking that the route does what you want:
    it 'should route properly' do
      pg = FactoryGirl.create(:product_group)
      {:post =>"/product_groups/#{pg.id}/announcements", 
       :product_group_id => pg.id.to_s}.should route_to('announcements#create',
                                                        :product_group_id => pg.id.to_s)
    end


For checking that you can accomplish this action successfully or not:

    it 'fails if not logged in' do
      pg = FactoryGirl.create(:product_group)
      post :create, 
           :product_group_id => pg.id, 
           :format => :js
      response.status.should eql(401)
    end

    it 'creates a new announcement with good params' do
      user = FactoryGirl.create(:user)
      sign_in user
      post :create, 
           :user_id => user.id, 
           :announcement => { :content => Faker::Lorem.sentence }, 
           :format => :js
      response.should be_success
    end



What you CANNOT do is directly quote the output of rake routes, i.e. you cannot do the following:
      pg = FactoryGirl.create(:product_group)
      post "/product_groups/#{pg.id}/announcements" 
             :product_group_id => pg.id, 
             :format => :js
      response.status.should eql(401)


This will raise ActionController::RoutingError. Why, I don't know, but the routing refuses to correctly interpret the explicit path in this case, despite the fact that the route test above works!

Tags:

jQuery + jQuery = no extensions


This is my own fault and is a reminder to myself for the next time I have this problem.

As documented on their front page, which I should have read before upgrading :P, jquery-rails for Rails 3.1 automatically inserts
//= require jquery
and
//=require jquery_ujs
into your application.js.

I couldn't figure out why two of my extensions stopped working. I couldn't figure out why all of a sudden I was loading two copies of jQuery. Plus, I couldn't figure out who was asking for a version of jQuery I didn't want yet, and where it was getting it from - Chrome insisted it was localhost, but I did not see a copy lying around in my source tree.

This is what I did to (successfully) debug it:
First I blew everything away in #{Rails.root}/tmp.

In the Chrome developer window, I put a breakpoint at the beginning of both jquerys, and one after Datepicker is loaded. This is how I found out that the 2nd loaded jQuery was blowing away all my previously loaded jQuery extensions.

In my source tree I did grep -R jquery\.js ./* and got the following:

Binary file ./tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 matches
Binary file ./tmp/cache/assets/D9D/A50/sprockets%2F1abc6eced0f709e935bada8961f05750 matches
Binary file ./tmp/cache/assets/DC7/AF0/sprockets%2Fcec0e140d887c53da709b8befad2315d matches


When I looked at the second file that was when I discovered that the offending version was being loaded from jquery-rails gem. Oh, huh:

^F;^@FI"^Vdependency_digest^F;^@F"%29738eb6ce64d47e73f841bbdd9ecad8I"^Srequired_paths^F;^@F[^FI"j/Users/squeedle/.rvm/gems/ruby-1.9.2-p318/gems/jquery-rails-2.0.2/v endor/assets/javascripts/jquery.js^F;^@FI"^Udependency_paths^F;^@F[^F{^HI" path^F;^@FI"j/Users/squeedle/.rvm/gems/ruby-1.9.2-p318/gems/jquery-rails-2.0.2/vendor/as sets/javascripts/jquery.js^F;^@FI"
9409 mtime^F;^@FI"^^2012-04-06T12:41:40-07:00^F;^@FI"^Kdigest^F;^@F"%aeef0ce303adf226ff97e8c6608baf57I"^M_version^F;^@F"%aa7d0db7619379e13b08335dee027df2


So of course, I was getting the version I wanted from Google's CDN site, adding the extensions we were using, and then the require in application.js was "helpfully" overwriting jQuery namespace with the one from jquery-rails, thus blowing away all the extensions we were using. Lesson: always read release notes before you upgrade :/

The confusing and most misleading part to all this is this has been working for quite some time. We switched to jquery-rails/Rails 3.1 long ago and yet these extensions stopped working only last week, so I'm still not sure what triggered the failure.

Also: thanks to bundler 1.1's addition of the 'outdated' command, I intend to lock down all production versions of gems we are using so that we can mindfully choose to upgrade next time. No more "~>" for us.

Last note for use by search engines: One of the symptoms was, "nimbleLoader has no method 'showLoading'" .

After upgrading from Snow Leopard to Lion, and getting

unknown0026bb1de3ec:dudada-alt squeedle$ bundle exec rake sunspot:solr:start --trace
** Invoke sunspot:solr:start (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute sunspot:solr:start
rake aborted!
Operation not permitted
/Users/squeedle/.rvm/gems/ruby-1.9.2-p318/gems/sunspot_solr-1.3.0/lib/sunspot/solr/server.rb:61:in `kill'
/Users/squeedle/.rvm/gems/ruby-1.9.2-p318/gems/sunspot_solr-1.3.0/lib/sunspot/solr/server.rb:61:in `start'
/Users/squeedle/.rvm/gems/ruby-1.9.2-p318/gems/sunspot_solr-1.3.0/lib/sunspot/solr/tasks.rb:12:in `block (3 levels) in '
/Users/squeedle/.rvm/gems/ruby-1.9.2-p318/gems/rake-0.9.2.2/lib/rake/task.rb:205:in `call'
/Users/squeedle/.rvm/gems/ruby-1.9.2-p318/gems/rake-0.9.2.2/lib/rake/task.rb:205:in `block in execute'
/Users/squeedle/.rvm/gems/ruby-1.9.2-p318/gems/rake-0.9.2.2/lib/rake/task.rb:200:in `each'
/Users/squeedle/.rvm/gems/ruby-1.9.2-p318/gems/rake-0.9.2.2/lib/rake/task.rb:200:in `execute'
/Users/squeedle/.rvm/gems/ruby-1.9.2-p318/gems/rake-0.9.2.2/lib/rake/task.rb:158:in `block in invoke_with_call_chain'


I looked at the relevant code in sunspot:

begin
Process.kill(0, existing_pid)
raise(AlreadyRunningError, "Server is already running with PID #{existing_pid}")
rescue Errno::ESRCH


It seems that the upgrade install of Lion may have changed permissions on the file or something. A permissions error isn't caught by this area of code so it just barfs and doesn't tell you why.

Solution: Just remove all your old pid files in test and development:

rm solr/pids/development/sunspot-solr-development.pid

Latest Month

November 2013
S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930

Syndicate

RSS Atom
Powered by LiveJournal.com
Designed by Terri McAllister