Mentoring 101 Draft Hidden Sticky

Posted Wednesday, 12 June 2013 | Post Comment |

This year my colleagues at Artsy created a formal fellowship program. We went out to many US colleges to recruit some of the brightest seniors. From thousands of applications we’ve selected a dozen people that will be joining the arts and tech teams. A few have already graduated and might get full time job offers at the end, others will go back to finish school. We assign everyone a mentor. Today I gave a “Mentoring 101” talk to the team, which seems to have turned out great, thanks to the excellent material sourced from the fellow members of the New York CTO Club, a group that combines several generations of management experience. Slides here.

image

What is Mentoring?

Good companies value people over product. It’s not a coincidence that most successful CEOs prioritize hiring the best people over making the best product or money. Getting the strongest people at any level and keeping them is probably the single hardest thing in any organization.

And so, to help build the best company, mentoring is putting people’s goals first, before their work. It’s unlike managing, which is making sure the right things get done. Mentoring is a process of developing people, and helping them achieve their goals. Successful people will, in turn, do the right things, and make the company successful. And so, good personal goals align with company’s goals to a large extent.

Mentoring is a huge responsibility and the mentor is directly responsible for the mentee’s success or failure.

What does a Mentor Do?

Most interns and apprentices come prepared with some domain knowledge. Our Art fellows know a thousand times more than me about art. Our Engineering fellows know more about technology than many of our art team members. Yet, none of them have any idea about how our company operates and, therefore, don’t know how to behave. Mentees will try to constantly adjust and to fit expectations. A mentor’s job is to provide an environment in which the mentee can succeed, including telling them what’s expected, what can, should or should not be done.

Start by setting expectations. I expect an Engineering fellow to deliver the same software quality as any experienced engineer, but over a longer timeframe, with a lot more help and with a smaller scope. I want my Engineering fellows to write code indistinguishable from the code of the most experienced Engineers on the team. I don’t care about how much of it they write, how long it takes and how much we’re going back-and-forth,  I just want to see progress, learning and keep them accountable to the same level of quality as I do for myself or anybody else on the team.

You want your mentee to stay on track. Set goals. These can be as simple as becoming fluent in a specific framework or language or as specific as building an end-to-end feature that spans a front-end and a back-end. Create frequent milestones, always being very verbose about what should come next. A good first milestone for a software Engineer is to get a working local system running and to commit documentation updates to the Getting Started guide that is always slightly out-of-date. Next, they could fix a bug. Then build a tiny feature that is mostly copy-paste from another similar feature. Deploy it to production. See someone use it.

The complexity of what the mentee is working on should escalate, but not overwhelm. There should be enough latitude to be a bit creative, too. Success must be easily achievable, and failure put in a positive light. On that note, failing is probably the single hardest thing to teach. I look for opportunities in which the mentee can make a mistake, and have a nice, controlled landing and a positive outcome. Either way, it must be made clear that the individual has complete control and ownership over what they are doing, the responsibility for doing their best, your support and trust. You’ve got their back, too.

Mentoring is a big time sink and a mentor must make the mentee a priority. I will generally stop what I am doing when interrupted by a mentee, whereas I’m likely to tell my boss to talk to me later. Answer questions, unless the answer may be found on the first page of a Google search. Use these interruptions as an opportunity to remind the mentee what’s important and always suggest ways for them to focus. Return the favor and interrupt them if they have been going on a tangent or if they look or sound frustrated. Redirect frequently and help the mentee finish what they started. At our sprint demos everyone presents what they worked on to the entire team, including mentees. It takes courage to stand in front of a big group and show a tiny feature.

Don’t keep the mentee in a bubble. Expose them to as many people as possible, and take them to meet a client.

Praise the mentee when they have done a good job. Take responsibility and protect them when they create a mess.

Finally, mentoring is a learning experience for the mentor. Encourage your mentee to give you feedback. A good way to start is to discuss existing practices and obstacles, making it about things, not people. Eventually, a productive dialog may yield feedback about your actual mentorship.

Finally, your mentee will go places and you might create a long lasting working relationship.

Are you a Mentor?

In technology there’re two classic career paths. The first, is a technical one – an Engineer becomes an Architect, becomes a CTO. The second is a management one – the Engineer becomes a Team Lead, a Development Manager and a VP of Engineering. I knew I was a manager when I was able to choose people responsibilities over exciting new technology, without looking back.

Mentoring is a first concrete step towards managing, but it’s not for everybody. Delegating is hard. Interacting with people is hard. Try it out, rise to the challenge.

 

How To Reject Engineering Candidates Draft Hidden Sticky

Posted Saturday, 25 May 2013 | Post Comment |

Over the past 15 years I have interviewed hundreds of Engineers. I had the pleasure of hiring quite a few, but I also had the duty to reject many.

It’s pretty easy to reject a candidate: ask HR to do it, or copy-paste a canned response and press “Send”.

“Thank you for coming to interview with us. Unfortunately we decided that we don’t have a good fit at this time.”

It’s also very, very wrong and borderline insulting.

As a hiring manager, I usually spend an hour over coffee with each candidate and try to figure out whether I want them on my team and whether I think they stand a chance in an in-person interview. I get to know them a bit, break the ice, tell them about my team and our company, try to dig up any obvious red flags. I spend another hour researching the information available online, read their code or pull requests, and occasionally reach out to my contacts that might know them. The onsite interview typically includes at least two busy Engineers, and at least one, equally busy, non-Engineer. Feedback is discussed throughout this process. In some occasions we’ll do references, yet still reject a candidate at the end. This process adds up to a full person/day and is both important and expensive.

So, take the time to write an extra paragraph and tell the interviewee why they were rejected!

I usually go through all the notes by the interviewing team and digest them into my best attempt at constructive feedback, including the positive elements. I find it really hard and I often spend thirty minutes for a draft and show it to at least one other person before sending. I agonize over this: rejection is bad news, and I don’t take it lightly.

The following are some actual examples of what I’ve written this past year.

We appreciate your huge desire to learn and your creative instinct. You're obviously excited to code and solve hard problems. But tech-wise we don't think you meet the bar that we're aiming for a candidate for this position. We do think you have a lot of potential.

We think you're very energetic and ambitious. You take initiative and are generally curious. Things like your involvement in your school’s programming club and your personal project X speak for themselves. However, your fundamentals in CS and the responses to technical questions were below the bar that we have set for a candidate in this position.

We think that there's a very strong culture fit and we love your positive energy. However, we would have liked to see a much stronger technical match. We encourage you to continue building up your experience.

We think you've done quite a few interesting projects and have an impressive learning tech curve. The feedback from the interviewers was that you did very well around the tech areas, but that you had trouble connecting with the interviewer. We call that “culture fit” and value it tremendously. We encourage you to practice your interviewing skills, so you can fully take advantage of your superior technical abilities.

Everyone who talked to you agreed that you have a lot to offer and that you're a capable engineer. You would likely fit nicely in the existing team and contribute at par. However, we only have one opening in this team at the moment, and we are going to continue looking for someone with a much more active open-source presence and more seasoned commercial product experience.

We think you have a good background, with interesting UX experience in human-computer interaction, mobile and Ruby back-end. You also worked with a great team at Company X. You experience is still a bit short and maybe too focused on the back-end of things. All things considered, we didn't see a sufficiently good fit for us.

We think you definitely have solid skills acquired at Company X and a track record prior to that. We don't think that it's sufficient, though, compared to the objectives we've set for our next hire for this position.

We have a large pool of candidates that are technically very strong, and you're clearly one of them. I also think that coming from an open-source connection is the best possible place to come from. On the tech side you have a large diversity of skill, your work speaks for itself and you have a ton of relevant experience for us in areas like video. But overall we don't see you fit well in this team from the cultural fit perspective, which we value as much, if not more, than technical ability.

We appreciate your interests in algorithms and technology in general and, of course, in working with us on our team X. However, we don't believe that your experience and skill level as of today are going to be what we're looking for.

These aren’t perfect and they stay pretty general, but they aren’t canned bullshit responses either. Each is a summary of the feedback by the interviewing team and represent how I feel. The candidates deserve at least this. And I think I never want to see this candidate again, I will offer my help and follow through if they want it. This may be an introduction or a referral to a specific company or person.

Finally, as candidate, you should always reply to rejection emails, if only to acknowledge that you have received it and thanking the interviewing company for their time.

Can we do better? How do you reject candidates?

 

Building & Scaling a Test-Driven Culture @ AppNexus (Video) Draft Hidden Sticky

Posted Thursday, 16 May 2013 | Post Comment |
I gave a talk last week at AppNexus on building and scaling a test-driven culture.

http://www.youtube.com/watch?v=QvHf94hxzRc

image
 

Being Helpful with Ruby Exceptions and Error Messages Draft Hidden Sticky

Posted Tuesday, 14 May 2013 | Post Comment |

We talk a lot about error handling in Ruby. But we rarely talk about raising errors and creating helpful error messages that are actionable. A good error should tell the developer what went wrong and what to do about it.

One library is known for its excellent error messages. Consider a typical validation error from Mongoid.

  1. #<Mongoid::Errors::Validations:
  2. Problem:
  3.   Validation of User failed.
  4. Summary:
  5.   The following errors were found: Password can't be blank
  6. Resolution:
  7.   Try persisting the document with valid data or remove the validations.>

This error describes the problem, offers a detailed summary and provides a possible resolution!

Lets implement a similar system for the ruby-enum gem that I live-coded at NYC.rb.

First, add a dependency on i18n and require "i18n". Then, create a lib/config/locales folder and an en.yml file in it. English error messages will go there. This file will need to be loaded by our library, specifically in ruby-enum.rb.

  1. require 'i18n'
  2. I18n.load_path << File.join(File.dirname(__FILE__), "config", "locales", "en.yml")

Error descriptions inside en.yml contain the problem, summary and resolution. The YAML format supports multi-lines with \_\_ and can include values from parameters using the %{name} syntax.

  1. en:
  2.   ruby:
  3.     enum:
  4.       errors:
  5.         messages:
  6.           uninitialized_constant:
  7.             message: "Uninitialized constant."
  8.             summary: "The constant %{name}::%{key} has not been defined."
  9.             resolution: "The enumerated value could not be found in class %{name}.\n
  10.             \_Use 'define' to declare it.\n
  11.             \_Example:\n
  12.             \_\_module %{name}\n
  13.             \_\_\_include Ruby::Enum\n
  14.             \_\_\_define %{key}, 'value'\n
  15.             \_\_end"

The base error class, Ruby::Enum::Errors::Base takes care of the translation. I stripped the implementation details below – the important parts is the BASE_KEY value for localized error messages and the compose_message method. Get the full implementation here and modify it for your project.

  1. module Ruby
  2.   module Enum
  3.     module Errors
  4.       class Base < StandardError
  5.  
  6.         attr_reader :problem, :summary, :resolution
  7.  
  8.         def compose_message(key, attributes = {})
  9.           @problem = create_problem(key, attributes)
  10.           @summary = create_summary(key, attributes)
  11.           @resolution = create_resolution(key, attributes)
  12.  
  13.           "\nProblem:\n  #{@problem}" +
  14.           "\nSummary:\n  #{@summary}" +
  15.           "\nResolution:\n  #{@resolution}"
  16.         end
  17.  
  18.         private
  19.  
  20.           BASE_KEY = "ruby.enum.errors.messages" #:nodoc:
  21.  
  22.           # implementation of create_problem, summary and resolution
  23.  
  24.       end
  25.     end
  26.   end
  27. end

Specific errors derive from this class.

  1. module Ruby
  2.   module Enum
  3.     module Errors
  4.       class UninitializedConstantError < Base
  5.         def initialize(attrs)
  6.           super(compose_message("uninitialized_constant", attrs))
  7.         end
  8.       end
  9.     end
  10.   end
  11. end

When raising an UninitializedConstantError, pass the values of key and name used in the en.yml file above.

  1. raise Ruby::Enum::Errors::UninitializedConstantError.new({
  2.   :name => "Class",
  3.   :key => "CONSTANT"
  4. })

Here’s the result.

  1. 1.9.3-p362 :002 > require 'ruby-enum'
  2. => true
  3. 1.9.3-p362 :003 > raise Ruby::Enum::Errors::UninitializedConstantError.new({
  4. :name => "Class",
  5. :key => "CONSTANT"
  6. })
  7.  
  8. Ruby::Enum::Errors::UninitializedConstantError:
  9. Problem:
  10.   Uninitialized constant.
  11. Summary:
  12.   The constant Class::CONSTANT has not been defined.
  13. Resolution:
  14.   The enumerated value could not be found in class Class.
  15.   Use 'define' to declare it.
  16.   Example:
  17.    module Class
  18.     include Ruby::Enum
  19.     define CONSTANT, 'value'
  20.    end

Beautiful.

 

Your First Ruby Gem Draft Hidden Sticky

Posted Tuesday, 14 May 2013 | Post Comment |

I live-coded a new gem called Ruby::Enum at NYC.rb on Tuesday. This library adds enum-like functionality to Ruby.

Here’s my checklist for creating a new gem.

Check the Name

Ruby gems are registered with Rubygems and managed in your projects using Bundler. Search for the new gem name on Rubygems to make sure it's not taken.

Create a Folder

I organize all my code in source and since I often fork code from others to contribute, create a subfolder with the Github username, including mine.

  1. $ mkdir ~/source/ruby-enum/dblock
  2. $ cd ~/source/ruby-enum/dblock

Initialize a Git Repository

  1. $ git init
  2. Initialized empty Git repository in /home/dblock/source/ruby-enum/dblock/.git/

Create a Github Repo

Create a new repository on Github.

image

Add it as a remote.

  1. $ git remote add origin git@github.com:dblock/ruby-enum.git

Create a Readme

Documentation is written in Markdown. Create and commit a README.md.

  1. $ git commit -m "Added README."
  2. [master acc5880] Added README.
  3. 1 file changed, 4 insertions(+)
  4. create mode 100644 README.md

Push the README to Github.

  1. $ git push origin master
  2. Counting objects: 6, done.
  3. Compressing objects: 100% (5/5), done.
  4. Writing objects: 100% (6/6), 963 bytes, done.
  5. Total 6 (delta 0), reused 0 (delta 0)
  6. To git@github.com:dblock/ruby-enum.git
  7. * [new branch]      master -> master

Add a License

Every project needs a license. I use the MIT license because it’s short and nobody has time to read licenses. Add a copyright notice to the README, don't forget future contributors.

  1. Copyright (c) 2013, Daniel Doubrovkine and Contributors. All Rights Reserved.
  2.  
  3. This project is licenced under the [MIT License](LICENSE.md).

Gemfile

A Gemfile is something that comes with Bundler and declares gem dependencies.

Install Bundler.

  1. $ gem install bundler
  2. Fetching: bundler-1.3.5.gem (100%)
  3. Successfully installed bundler-1.3.5
  4. 1 gem installed
  5. Installing ri documentation for bundler-1.3.5...
  6. Installing RDoc documentation for bundler-1.3.5...

Create a Gemfile. For now it just says where to get other gems from.

  1. source "http://rubygems.org"

Run bundle install.

  1. $ bundle install
  2. Resolving dependencies...
  3. Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

.gitignore

The generated Gemfile.lock should not be included, create a .gitignore.

  1. Gemfile.lock

Enum Library

Create lib/ruby-enum.rb and lib/ruby-enum/version.rb.

  1. require 'ruby-enum/version'

  1. module Ruby::Enum
  2.   VERSION = '0.1.0'
  3. end

Tests

You. Must. Test.

Add RSpec to Gemfile.

  1. gem "rspec"

Tests need some setup, specifically to load the code in lib. Create spec/spec_helper.rb.

  1. $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
  2.  
  3. require 'rubygems'
  4. require 'rspec'
  5. require 'ruby-enum'

Create a test in spec/ruby-enum/version.rb.

  1. require 'spec_helper'
  2.  
  3. describe Ruby::Enum do
  4.   it "has a version" do
  5.     Ruby::Enum::VERSION.should_not be_nil
  6.   end
  7. end

Add .rspec to pretty-print test output.

  1. --format documentation
  2. --color

Gem Declaration

A ruby-enum.gemspec is a gem declaration.

  1. $:.push File.expand_path("../lib", __FILE__)
  2. require "ruby-enum/version"
  3.  
  4. Gem::Specification.new do |s|
  5.   s.name = "ruby-enum"
  6.   s.version = Ruby::Enum::VERSION
  7.   s.authors = [ "Daniel Doubrovkine" ]
  8.   s.email = "dblock@dblock.org"
  9.   s.platform = Gem::Platform::RUBY
  10.   s.required_rubygems_version = '>= 1.3.6'
  11.   s.files = `git ls-files`.split("\n")
  12.   s.require_paths = [ "lib" ]
  13.   s.homepage = "http://github.com/dblock/ruby-enum"
  14.   s.licenses = [ "MIT" ]
  15.   s.summary = "Enum-like Behavior for Ruby"
  16. end

The declaration can be loaded in Gemfile, so that we can list dependencies in one place.

  1. source "http://rubygems.org"
  2.  
  3. gemspec

When running under Bundler, the Gemfile will automatically be loaded, which will automatically load the gem specification.

  1. $ bundle exec irb
  2. 1.9.3-p362 :001 > require 'ruby-enum'
  3. => true
  4. 1.9.3-p362 :002 > Ruby::Enum::VERSION
  5. => "0.1.0"

Rakefile

Bundler comes with a number of Rake tasks to release a gem. Add Rake to Gemfile.

  1. gem "rake"

Create a Rakefile.

  1. require 'rubygems'
  2. require 'bundler/gem_tasks'
  3.  
  4. Bundler.setup(:default, :development)

  1. $ rake -T
  2. rake build    # Build ruby-enum-0.1.0.gem into the pkg directory.
  3. rake install  # Build and install ruby-enum-0.1.0.gem into system gems.
  4. rake release  # Create tag v0.1.0 and build and push ruby-enum-0.1.0.gem to Rubygems

  1. $ rake build
  2. ruby-enum 0.1.0 built to pkg/ruby-enum-0.1.0.gem.

Add pkg to .gitignore.

Default Rakefile to Running Tests

  1. require 'rspec/core'
  2. require 'rspec/core/rake_task'
  3.  
  4. RSpec::Core::RakeTask.new(:spec) do |spec|
  5.   spec.pattern = FileList['spec/**/*_spec.rb']
  6. end
  7.  
  8. task :default => :spec

Travis-CI

Add .travis.yml, register the project on travis-ci.org and add a badge.

  1. rvm:
  2.   - 1.8.7
  3.   - 1.9.3
  4.   - 2.0.0
  5.   - jruby-19mode
  6.   - rbx-19mode

  1. [![Build Status](https://travis-ci.org/dblock/ruby-enum.png)](https://travis-ci.org/dblock/ruby-enum)

image

Enum Library Code

Include ruby-enum/enum. See enum.rb and enum_spec.rb for the implementation.

Changelog

Create a CHANGELOG to list current and future updates.

  1. ### 0.1.0 (5/14/2013)
  2.  
  3. * Initial public release - [@dblock](https://github.com/dblock).

Contributing

Add a contributing section to README.

  1. * Fork the project.
  2. * Make your feature addition or bug fix with tests.
  3. * Update CHANGELOG.
  4. * Send a pull request. Bonus points for topic branches.

Release the Gem

  1. $ rake release

Prepare for Next Release

Bump the version, add a Next Release section to CHANGELOG.md.

  1. ### Next Release (TBD)
  2.  
  3. * Your Contribution Here

Source Code

All source code for the above can be found at https://github.com/dblock/ruby-enum.

 

Grape vs. Poncho Draft Hidden Sticky

Posted Saturday, 06 April 2013 | Post Comment |

There’re a number of excellent micro-frameworks to author RESTful APIs in Ruby. Let’s take a look at the newcomer, Poncho, from the Stripe team, brought up on the Grape mailing list. For those that don’t know me, I’m the maintainer of Grape and use it very heavily at Artsy. I’ll do my best not to be biased.

With Poncho you start by declaring resources that inherit from Poncho::Resource. A resource is a prescriptive way of declaring what parameters to expect and what results to render from the API. In many ways resources are similar to Grape’s entities, except that the latter are no longer part of Grape and you can use roar, rabl or any other framework to render results - you choose. Poncho resources include parameter validation, which makes sense. Personally, language matters, so I would not call values that can be assigned to the resource parameters, but maybe fields or attributes.

You then declare a Poncho::JSONMethod, which inherits from Poncho::Method, which is a piece of middleware. The former is equivalent to a Grape formatter, and the latter is equivalent to the Grape endpoint Rack middleware. You have to override the invoke method and implement your business logic.

How does all this come together?

  1. # poncho
  2. get "/users", & UsersListMethod

  1. # grape
  2. get "/users" do
  3.    ...
  4. end

Grape could easily support the Poncho syntax with a few lines of code. Internally it creates a Proc from the body of the block.

I think that Poncho is in the very early days of development and has made some choices that Grape already made a year or two ago and decided undo more recently. Poncho hasn’t dealt with more complicated problems like versioning or content-negotiation, yet. Once it does, poncho contributors will find that infrastructure begins to bloat and will likely split it the same way we split grape and grape-entity. My current view is that the API DSL layer should be providing functionality closer to the HTTP protocol and a separate entities-like library should deal with data representation. That’s because I have strong opinions that a modern API should be a Hypermedia one, but I would not want to impose this on anyone, which is incidentally a similar philosophy that lead to  Webmachine (check out my earlier Grape vs. Webmachine post).

That said, none of the above is difficult to accomplish.

I would certainly have preferred if Stripe chose Grape as the API DSL and implemented their style of data presenters if they felt strongly about that. But we all want our own micro frameworks, don’t we?

 

Doctors, Surgery and Open-Source Draft Hidden Sticky

Posted Wednesday, 27 March 2013 | Post Comment |

I visited a friend who lives in a remote, tropical region of the United States. He’s a doctor and a practicing eye surgeon. The island has both the very rich and the extremely poor. It’s known for both the beautiful beaches and gun violence in poorer neighborhoods. There’re no Starbucks for over 50K residents. There’re a few richer patients that have good insurance or pay cash, but the majority are older natives with a large proportion on Medicare. A dozen surgeries or 60 patients a day is considered uneventful. A full night operating in the ER only happened once during our stay. There’re talks about closing the only hospital.

The phone rang in the middle of a dinner with a fellow doctor on the other end of the line, and our side of the conversation went something like this: “It sounds like this patient really needs to be seen by a doctor first thing tomorrow morning, so if she doesn’t have a Medicare coupon for a specialist, we’ll see her for free.” I asked him how that’s even an option? He replied that the money made with so many patients is good enough, and the health of the resident population is so precarious, that it just makes sense to be helpful as much as possible.

I think there’s a valuable lesson to be learned here for everyone writing software, too.

By all accounts we’re paid extremely well and we’re as much in demand as doctors. An even smaller percentage of us are the kind of specialists capable of building the software equivalent of performing eye surgery. Of course, there’s no true comparison with being able to directly affect one’s vision with a surgical instrument and the next website, but how can we use our privileged position to, at least, be more helpful? Here’re a few ideas.

If you can afford it, work for a non-profit. If you’re in NYC, I would start with DonorsChoose. Their Engineering team is lead by a very experienced techie and an amazing guy. They promise you’ll never get rich, but you’ll wake up every day with a purpose and heartwarming “thank you” emails from thousands of children in the public school system around the US.

For the socially-conscious that are looking for a startup experience, check out NYC’s Amicus. We shared an office at GeneralAssembly with their founder and CEO and the company has labored relentless helping non-profits be a lot more efficient in their fundraising. This means more money goes to the cause.

Continuing the theme of education, consider Neverware, which makes old computers run like new and who’s CEO is a volunteer firefighter.

Don’t work for anyone evil. One way to ensure that is to join a company that encourages, promotes and writes open-source. I try to practice this as much as possible by going the extra mile of creating new open-source projects, contributing to existing ones, answering questions on mailing lists and educating rising technologists without expecting anything in return. Software has eaten the world, so even if you don’t completely side with Richard Stallman’s vision of freedom activism, you could, maybe, compare the little bit of your open-source work you do to an occasional free visit to the doctor.

 

5 Anti-patterns in a College Grad Engineer’s Resume Draft Hidden Sticky

Posted Monday, 25 March 2013 | Post Comment |

A resume is what you did, it’s not who you are.

In the past few years I’ve collected dozens of resumes from junior Engineering candidates and have provided written feedback to those who wanted to improve. I found that the vast majority of resumes have similar anti-patterns, repeating mistakes that are a quick turn off for any hiring manager. If you are in school or a soon to be graduating computer science major and don’t want your resume to go to the garbage, read the following 5 anti-patterns.

Objectives Are Too Broad

image

“To obtain a full time position that matches my enthusiasm, constant effort and efficiency.”

An objectives paragraph creates unnecessary barriers in hiring you, at best. The above example limits you to full time offers, then just moves some air around. Don’t limit your search to full time positions, especially if you’re trying to relocate. Most companies I know will extend a full time offer if you do an amazing job as an intern. Remove this text and repeat after me: “Seeking a paid internship or full time programming position with an experienced Engineering team.”

Github is Your New Resume

“I am an open-source contributor …”

image

I wrote an article that went viral, Github is Your New Resume. When evaluating someone’s Github profile, I usually click on Repositories and then Sources. Do you have a project that you have started that has been heavily forked and contributed to? Do you have any activity that’s longer than a year ago or did you just throw some code up there to beef up your resume? Does your contributions graph really look like this?

image

I don’t expect a junior developer to have any of these things. Displaying a link to an empty Github profile is a terrible idea. Do link to your personal website.

You have Lead, Driven, Managed, Advised or Evangelized

image

“Advised xyz.com founders in technology selection.”

It reads like your head can barely squeeze through your chateau’s living room French doors! You are not the project’s lead because you’re the only programmer. You’re not an advisor because your friends started a website and wanted to know which language is cool. Downplay and humble-down every single word on paper. Let your results and references speak for your value, not your resume. Remove every single adjective or verb that isn’t “did”, “implemented” or “built”.

You Have Expert Skills

image

“Expert in C++, Photoshop and Excel.”

I recommend removing a list of skills altogether and writing, in tiniest font possible, the technologies used within your work experience.  Should you talk about source control that you have worked with on the resume? My answer is no: make sure to avoid the impedance mismatch between the tools and technologies that you describe. My rule of thumb – delete anything that’s not a programming language.

You Took Many Courses and Excelled in Clubs

image

“2nd Place in the Campus Green Computing Initiative”

Most of us who left college many years ago will roll our eyes when you ask about those college years.

I think your resume should demonstrate that you can make an effective transition from college to the workforce, which means leaving as much “college” behind as possible. Being a Teaching Assistant should go into your work experience, but your participation in chess club should be left out. I would also not include a mention of your GPA. And any work experience that you may have should be concise and explain what the project was and what you did within that project.

***

If you like the advice above, and are in college or a recent grad, send me a copy of your resume to dblock[at]dblock[dot]org. I promise to give it 15 minutes and email you a few bullet points of feedback.

 

Grape 0.4.0 Released w/ Stricter JSON Format Support & More Draft Hidden Sticky

Posted Sunday, 17 March 2013 | Post Comment |

I’m very excited to Release Grape 0.4.0 today. Again, thanks to the 10 (!) contributors to this release.

Is this a solid release? You bet. I’ve upgraded our largest API project at artsy.net to Grape 0.4.0 and all of the 1870 API specs have passed.

The complete CHANGELOG is here. There’re a few backwards incompatible changes that you might want to check out while you’re upgrading.

JSON and XML Formatter Changes

Until the 0.4.0 release Grape took a pragmatic approach to JSON response and request data. It was also incorrect.

If your API returned a an Object, it was translated to JSON via to_json or a MultiJson.dump call. This worked well for both Hash and Array, meanwhile Grape left objects of type String alone. This friendly method ensured that you could translate an object into a String, skipping all the hard work Grape’s formatter would otherwise have to do. Similarly, Grape tried to be helpful by ignoring any data that couldn’t be parsed into a hash and therefore retrieved via a call to params from a PUT or POST.

I have fixed this in @6fa8f59, released with Grape 0.4.0, and it’s now possible to return proper JSON representations of NilClass or String, as well as to parse any valid JSON, such as Array. This means that if your API implementation returned a String or a nil, the output will be different.

  1. get "/" do
  2.   "example"
  3. end
  4.  
  5. # Grape 0.3.x
  6. "example"
  7.  
  8. # Grape 0.4.0
  9. "\"example\""
  
  1. get "/" do
  2.   nil
  3. end
  4.  
  5. # Grape 0.3.x
  6. ""
  7.  
  8. # Grape 0.4.0
  9. "null"

You can monkey-patch back the old behavior as follows.

  1. module Grape
  2.   module Formatter
  3.     module Json
  4.       class << self
  5.         def call(object, env)
  6.           return object if ! object || object.is_a?(String)
  7.           return object.to_json if object.respond_to?(:to_json)
  8.           raise Grape::Exceptions::InvalidFormatter.new(object.class, 'json')
  9.         end
  10.       end
  11.     end
  12.   end
  13. end

Similar changes apply to the XML formatter.

Reading Input

With the above changes its now possible to read JSON input that’s not a hash. This was reported as a bug in #347. Hash parameters continue to be merged into params, while everything else is now available in env[‘api.request.body’], you don’t have to parse env[‘rack.input’] again, a notable performance optimization.

Default Log Format

Somewhere in version 0.3.2 the default logger format was inadvertently changed to be something like this.

  1. I, [2013-02-27T18:39:20.352350 #85986]  INFO -- : one line
  2. I, [2013-02-27T18:39:20.363543 #85986]  INFO -- : two lines

This was a side-effect of requiring all of ActiveSupport, reported and fixed in #353. The logger is now back to be its undecorated version without all those timestamps, levels or process IDs.

If you want the above behavior, require active_support/all.

 

ResourceLib 1.4 Released Draft Hidden Sticky

Posted Sunday, 03 March 2013 | Post Comment |

https://github.com/dblock/resourcelib

Download: http://code.dblock.org/downloads/resourcelib/Vestris.ResourceLib.1.4.zip

  • #2: Added VersionResource.FileFlags - @alaendle.
  • Updated solution to Visual Studio 2010 - @redwyre.
  • Added NUGet references for NUnit, NUnit.Runners, and MSBuildTasks - @redwyre.
  • Added more options to build.cmd: code, code_and_test and run_test_only - @redwyre.
  • Documentation rewritten in markdown - @dblock.

ResourceLib is a framework that enumerates resources and implements both read and write of the file version VS_VERSIONINFO, string resources such as company, copyright and product information, RT_GROUP_ICON and RT_ICON, RT_CURSOR, RT_BITMAP,RT_MENU, RT_DIALOG, RT_STRING, RT_ACCELERATOR, RT_FONT and RT_FONTDIR and RT_MANIFEST resources.

 
< | 1  2  3  4  5  6  7  8  9  10  11  ... >