Ruby Benchmarking 25 March 2018

Ruby Benchmarking

If you work on a large app, publish, gems, or are interested in the Ruby community at some point you will likely want to dig into performance and benchmarking. Often what you think will help performance doesn’t have as much of an impact as you would guess. Which is why being able to set up quick experiments to verify the impact of code changes on performance and memory can be important. Benchmarking is great as it can help prove, your change had the impact you want. Ruby performance and the measurement of it is getting more discussion at the moment because Ruby 3X3 set out a goal to make Ruby 3 three times faster than Ruby 2. Learn more in this talk, Ruby3x3: How are we going to measure 3x?

This post will talk about measuring the performance of Ruby and benchmarking your own code and applications. In a future post, I will dig more into good practices around benchmarking Ruby gems.

Stopwatch

image from pixabay

Ruby Benchmarking Projects

A number of projects have been proposed and have support from the community for benchmarking Ruby… These project all will help the community improve the performance of Ruby, and can be used to help you measure the impact or Ruby or Gem changes you would like to try. If you are interested in contributing to Ruby or helping the community with improved performance or better benchmarking I encourage you to check out these projects. A great way to learn more about benchmarking is to dig into projects that are already out available and looking for more contributors.

Ruby Benchmarking Basics

When I need to quickly benchmark something, I look no further than Ruby’s simple Benchmark Module. I don’t have all the usage memorized off the top of my head, but have ended up at this great blog post, timing Ruby code is easy with Benchmark, a number of times over the years. It is a quick and simple post that will help get basics up and running in no time at all. For some additional Ruby benchmarking support also see the resources below.

Learning by Benchmarking A Proposed Ruby Change

I previously covered how to build Ruby from scratch on OS X. I posted that as I was working on a feature, I was hoping to get into Ruby. I proposed a change to Ruby’s Coverage that I hoped would lead to large performance improvements adding Coverage Pause & Resume support. A little discussion with @tenderlove, lead me to try to prove the value of the feature in terms of performance. In the end, I actually proved my feature idea was unnecessary and that Ruby’s Coverage was significantly faster than Ruby’s Tracepoint. Below, I will walk through some of the steps and code, I used while driving towards better benchmarks and understanding of what was really impacting performance while trying to collect the line of code runtime.

First Attempt: A Micro Benchmark

For some specific changes a micro benchmark, that focuses in very narrowly on the specific changes under test can be all that is needed and make for faster and easier iteration while testing changes. Often these are the easiest to setup and be more easily repeatable with various versions and settings to compare a number of changes.

My first attempt was to use a small repository, that I had used to show an issue with Ruby’s coverage, see my Benchmarking Coverage Example. The code was extended it so it could be run in 3 modes:

  • Ruby without Coverage loaded: ruby example.rb
  • Ruby with Coverage as it exists in the current release: COVERAGE=true ruby example.rb
  • Ruby with my suggested Coverage feature put to use: ENHANCED_COVERAGE=true ruby example.rb
require 'benchmark'
require 'coverage'

WITH_COVERAGE = !!ENV['COVERAGE']
WITH_ENHANCED_COVERAGE = !!ENV['ENHANCED_COVERAGE']

Coverage.start if WITH_COVERAGE || WITH_ENHANCED_COVERAGE
require 'bigdecimal/math'
require './app'
require './app_proxy'
Coverage.pause if WITH_ENHANCED_COVERAGE

ITERATIONS = 2_000
UPTO = 1_000
coverage_data = nil

# warm up
AppProxy.process(App, {iterations: 1, up_to: UPTO})

Benchmark.bm do |bm|
  if WITH_ENHANCED_COVERAGE
    bm.report { coverage_data = AppProxy.process(App, {iterations: ITERATIONS, up_to: UPTO, coverage: false, enhanced_coverage: false}) }
  end
  bm.report { coverage_data = AppProxy.process(App, {iterations: ITERATIONS, up_to: UPTO, coverage: WITH_COVERAGE, enhanced_coverage: WITH_ENHANCED_COVERAGE}) }
end

puts "coverage"
puts coverage_data
puts "done"

The initial results, even with a high number of iterations basically couldn’t show a real difference. In the case, I was trying to show, since it wasn’t a dramatic improvement and wasn’t obviously measurable like the number of objects allocated to memory, proved to not be a good case for a microbenchmark.

Second Attempt: Build On Rails Ruby Bench

As I abandoned the idea of a microbenchmark being able to show the differences of the performance impact when using Ruby’s code coverage. I sought a more realistic example of how Ruby code is frequently used in production. I found @codefolio’s project, rails_ruby_bench, which I mentioned previously intends to help measure performance impacts for Ruby 3X3. Unfortunately, I ran into some issues getting this benchmark to run locally and I would need to do a good deal of work to embed the code I wanted under test into this project and Discourse which the project uses as the Rails app under performance testing.

While I didn’t end up pursuing this route, it did help push me towards a good direction to more realistically measure the performance impacts I wanted to see. By setting up a sample Rails application and testing full request cycles, I would have a much more realistic measure of my changes. I plan to follow up on this project more in the future and think it is an ideal way to test many Ruby or Gem changes that would have performance or memory impacts on standard Rails applications.

Third Attempt: Sample Rails App

Combining the learnings from the microbenchmark and the ideas in Rails Ruby Bench, I wanted to be able to quickly test a number of different scenarios by just setting a few environment variables, and then pull meaningful results on exercising the full Rails app with the changes. To measure the impact on the full Rails stack I turned to Apache’s AB, a simple HTTP benchmarking tool I have used many times over the years.

For each test, the Rails application would be run in a different mode, then benchmarked via AB. I created a new repository coverage_rails_benchmark. The project README covers all the steps for anyone to run their own set of benchmarks and records all the results of my performance tests.

The benchmarking script itself is extremely simple, the script below will make 2000 requests making 5 concurrent requests at a time to the endpoint listed. The code can be found in bin/benchmark.rb

puts `ab -n 2000 -c 5 "http://127.0.0.1:3000/posts"`

For example to get the most basic results of Ruby without Coverage loaded, one would follow the two steps below in two different terminals.

  • start the Rails server in basic mode: IGNORED_COVERAGE=true RAILS_ENV=production bin/rails server
  • execute the benchmark: ruby ./bin/benchmark.rb

This would output a bunch of data about the benchmark results.

Benchmarking 127.0.0.1 (be patient)

Server Software:
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /posts
Document Length:        3631 bytes

Concurrency Level:      5
Time taken for tests:   8.391 seconds
Complete requests:      2000
Failed requests:        0
Total transferred:      8572000 bytes
HTML transferred:       7262000 bytes
Requests per second:    238.34 [#/sec] (mean)
Time per request:       20.978 [ms] (mean)
Time per request:       4.196 [ms] (mean, across all concurrent requests)
Transfer rate:          997.58 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      0      11
Processing:     6   21  10.8     19     192
Waiting:        6   20  10.7     19     190
Total:          6   21  10.8     19     192

Percentage of the requests served within a certain time (ms)
  50%     19
  66%     23
  75%     25
  80%     26
  90%     30
  95%     33
  98%     38
  99%     42
 100%    192 (longest request)

For my various comparisons, I ended up caring the most for the mean time per request in the above example 20.978 [ms] (mean) was the starting point baseline I comparing with all other results. My final sample benchmark support 7 distinct modes that could be run in two different distinct settings. Unlike with my microbenchmark performance differences were extremely obvious with a full spread of fasted benchmarking mode running at 17.735 [ms] (mean) vs the slowest mode taking 85.069 [ms] (mean). Showing the worst mode was nearly 5X slower in a simple benchmark.

Benchmarking Conclusions

The various modes and options made it clear that I had initially been optimizing for the wrong thing, and that while there was significant performance improvements that could be made, it wouldn’t be related to my suggested Coverage feature proposal to support pause and resume. Instead, it showed that collecting coverage data was always very fast, but pulling and processing that data could be very slow. Opposed to trying to sample data collection the goal should be to reduce as much as possible the frequency one processes the results and to filter it down to the smallest set of results needed. Let’s take a look at a high-level summary below, or see the full benchmark details.

  • No Coverage Support: 17.735
  • Coverage Running (Ignore Coverage): 18.131
  • Coverage Stopped (Ignore Coverage): 18.268
  • Coverage Paused (Ignore Coverage): 18.717
  • Coverband Coverage (Ignore Coverage): 18.759
  • New Pilot Version Coveraband Coverage (Collect Coverage): 19.227
  • Coverage Running (Collect Coverage, but only into memory): 21.141
  • Coverage Resume (Ignore Coverage): 23.930
  • Coverage Resume (Collect Coverage, but only into memory): 26.720
  • Coverband Coverage (Collect Coverage): 39.421
  • Coverband Tracepoint (Collect Coverage): 46.979
  • Coverband Tracepoint (Ignore Coverage): 47.500
  • Coverage (Collect Coverage, send to Rails.logger): 85.069

In the end, my goal of changing Ruby’s Coverage was to be able to significantly reduce the performance overhead of my gem Coverband’s ability to collect runtime data. The results from the benchmark gave me all the data I needed to see that a different approach, where I dropped TracePoint in favor of Coverage but worked to reduce the frequency of checking the results would lead to far better performance improvements than my initially suggested feature. In the end, I pursued that approach, and was able to reduce the overhead with a sample rate of 100% from 2.5X slower to only being 1.08X slower! The details on that, I will cover in another post with some specifics on how to build performance benchmark testing into a Gem.

Ruby Benchmarking Learnings

I came away with a deeper understanding of Ruby performance benchmarking, and a much faster Gem that I will be able to release shortly. Beyond that some additional thoughts on Ruby benchmarking,

  • For some changes microbenchmarks aren’t helpful
  • There are some existing great projects to help folks benchmark changes to the Ruby language
  • Ruby’s Coverage is significantly Faster than collecting line usage via Ruby’s TracePoint functionality
  • Specific to Ruby’s Coverage library
    • The number of files instrumented with coverage has a big impact on performance, making micro benchmarks useless for that library
    • Calling coverage.peek_results to access the data is the biggest cost, much larger than collecting it.
    • Simply logging, processing, or trying to do anything with data is often slower than collecting it
    • Performance wins will come in reducing processing the data vs collecting it
  • Writing an maintaining good benchmarks can be challenging, I didn’t touch on the issues of running benchmarks with “background noise” and running multiple times to tease that out
  • Without measuring performance, guessing what will have a large impact is often wrong

Let’s Go Faster

via GIPHY

In a follow-up post, I will dig into the details of benchmarking a Gem over time, and the specific changes that helped to reduce the performance overhead of Coverband making it an order of magnitude faster. While there are code changes and using different features of Ruby, large performance wins also can come from a fundamentally different approach to solving the problem, which is the case with the changes needed to improve Coverband.

comments

Rack Proxy Tour 26 February 2018

Rack Proxy Tour

I wanted to share a quick tour of a flexible Ruby tool. I have turned to rack-proxy a number of times, throughout the years. It is a tiny and super useful Rack middleware that can quickly be adapted to perform a number of useful functions. While it is a small library it is a tool that has been handy for quick and lasting workarounds a number of times. It is a sharp tool, so be careful with it… Especially because it is severely lacking documentation… Perhaps I should send a documentation PR one of these days.

Job Challenge

image from pixabay

Rack Proxy Examples

Some of the various ways I have used Rack Proxy over the years, while I wouldn’t recommend all of them, sometimes a quick hack is needed and Rack proxy can be a powerful tool for that.

  • subdomain based pass-through to multiple apps
  • useful for handling awkward redirection rules for moved pages
  • fan out a single API request to multiple concurrent backend requests and merging results
  • authentication / authorization prior to proxying requests to a blindly trusting backend
  • avoiding CORs complications by proxying from same domain to another backend

Example Code

In the example below we will have our rack proxy middleware, handle user authentication and authorization then make an authenticated request to another service. In this case, any request to our Rails applications host with the path /example_service/ will pass through to the target service.

require 'rack-proxy'

class ExampleServiceProxy < Rack::Proxy
  def perform_request(env)
    request = Rack::Request.new(env)

	 # path matches our target &&
	 # user auth (devise in this case) found a logged in user
    if request.path =~ %r{^/example_service} &&
      env['warden'] &&
      env['warden'].user

		# have a user but using CanCan check if user has needed permissions
      if env['warden'].user.can?(:access, :access_example_service)
        token = "Bearer #{Settings['service.token']}"
        service_url = Settings['service.url']

        @backend = URI(service_url)
        env['rack.backend'] = @backend
        
        # while documentation says you only need on of these,
        # I needed to set them all to have the expected results
        env['REQUEST_PATH'] = env['REQUEST_URI'] = env['PATH_INFO'] = '/api/target_service_path'
        
        # target service fails on cookies
        env['HTTP_COOKIE'] = ''
        env['HTTP_AUTHORIZATION'] = token
        super(env)
      else
        Rails.logger.info "example_service: 401 user #{env['warden'].user.inspect} denied"
        [401, {}, ['Unauthorized!']]
      end
    else
      @app.call(env)
    end
  end
end

Then you can just hook up the middleware as needed, using something like below (in application.rb for example).

config.middleware.use(ExampleServiceProxy)

If you want to be able to access the devise user env['warden'].user you will need to make sure your middleware is inserted after the devise middleware. You can quickly check the order by printing out the Rails middleware stack.

> rake middleware

use Raven::Rack
use BufferedLoggingMiddleware
...
use Warden::Manager
use ExampleServiceProxy
...
use OtherExamples
comments

Building Your Own Ruby 17 February 2018

Building & Using Your Own Ruby

If you want to work on changes or learn more about the internals of the Ruby language, you can alter the source and build your own from scratch. It isn’t that hard or scary, you will learn a bit more about Ruby just by building it. This is a quick start to building Ruby from scratch on OSX, and using it to run your local apps.

If you want to read a great guide about contributing to Ruby, it also covers how to build even easier via a Dockerfile.

Get the Source

Use git or SVN to pull the source repo.

  • I like git, so I forked the Ruby project.
  • Then clone it: git clone [email protected]:danmayer/ruby.git
  • go into the directory and take a look around.

Build Trunk Before Modifying

Before you make any modifications, I recommend you get the current trunk building and test running your apps with it. Then you can create a branch and see the impact of any modifications you would like to try out.

Building Yourself

I recommend using the Ruby-buil instructions below as I continued to hit issues with building from scatch with my own options related to SSL.

If you want to give it a shot thought, run the 4 commands below and it will compile and install Ruby from src on your system.

aclocal
autoconf
bash -c './configure'
make && make install

If you get this error about OpenSSL:

openssl:
	Could not be configured. It will not be installed.
	Check ext/openssl/mkmf.log for more details.
*** Fix the problems, then remove these directories and try again if you want.

It is a bit hard to resolve on OS X yourself, but luckily we can just use ruby-build to do the work for us, see below.

Building via Ruby-build

Ruby build will detect and use SSL from homebrew and avoid the broken OSX implementation.

  • install ruby-build: brew install ruby-build
  • copy the current dev trunk target: cp /usr/local/Cellar/ruby-build/20171226/share/ruby-build/2.6.0-dev /usr/local/Cellar/ruby-build/20171226/share/ruby-build/2.6.0-mine
  • edit the file (...ruby-build/2.6.0-mine) to point to your fork: ... install_git "ruby-trunk" "https://github.com/danmayer/ruby.git" ...
  • build from your git to the ~/.rubies/ directory: ruby-build 2.6.0-mine ~/.rubies/ruby-2.6.0mine
    • run from the build dir: /usr/local/Cellar/ruby-build/20171226/share/ruby-build
  • make sure to open a new shell so ChRuby (or RbEnv) find the new ruby.
  • you can now reference the new build in your .ruby-version file in any project

If you want to build from your local git to avoid pushing to a remote branch while testing this is how your build file should end up.

install_package "openssl-1.1.0g" "https://www.openssl.org/source/openssl-1.1.0g.tar.gz#de4d501267da39310905cb6dc8c6121f7a2cad45a7707f76df828fe1b85073af"  mac_openssl --if has_broken_mac_openssl
install_git "coverage_pause" "/Users/danmayer/projects/ruby" "feature/coverage_pause" ldflags_dirs autoconf standard_build standard_install_with_bundled_gems verify_openssl

If all is working as expected you should see this.

ruby-build 2.6.0-coverage ~/.rubies/ruby-2.6.0coverage
ruby-build: use openssl from homebrew
Cloning https://github.com/danmayer/ruby.git...
Installing coverage_pause...
ruby-build: use readline from homebrew
Installed coverage_pause to /Users/danmayer/.rubies/ruby-2.6.0coverage

Playing Nice with Other Rubies?

If you are like most Rubyists you have a number of Rubies installed, beyond the default OSX Ruby, using something like RBenv, RVM, or ChRuby.

  • The default OS X Ruby should be: /usr/bin/ruby
  • If you build from scratch the default target will be installed to: /usr/local/bin
    • This can cause some issues with various Ruby environment managers
    • adjust your path to target this Ruby or your normal one
    • Another reason I recommend building via ruby-build, as it will work easier with most Ruby environment managers
  • Ruby build will put ruby into the ~/.rubies
    • with ChRuby it will automatically pick these up

Then you can reference your new custom ruby in a .ruby-version file at the root project directory, for example:

# .ruby-version
ruby-2.6.0coverage

Running an App with your Custom Ruby

After building your own Ruby and setting the .ruby-version you should be good to go. You can verify you are running your Ruby by adding some simple print statement. Pick a favorite Ruby method and just add a print statement like so…

printf( "hello from my method!\n" );

  • push the change to the branch your referenced in your Ruby build steps
    • there are ways to build locally, but I have just targetted git branches
  • rebuild Ruby: ruby-build 2.6.0-coverage ~/.rubies/ruby-2.6.0coverage
  • enter your project iwth the set ruby-version
  • run ruby -v to make sure it matches expectations
    • if you get chruby: unknown Ruby: ruby-2.6.0coverage either refresh chruby or open a new terminal so it picks up the new build
  • now run things as you normally would…
# in Rakefile
desc "call coverage running"
task :call_coverage_running do
  require 'coverage'
  Coverage.running?
end
rake call_coverage_running
hello from Coverage.running

In the above output, I can see that I am runnin my custom Ruby branch as I had added a print messaged to the Coverage.running? method.

Testing your Custom Ruby

If you are trying to do some real work on Ruby other than exploring, you will want to be able to run the tests on files after you modify them, and add your own tests.

Running Tests

For example to run a specific test file, you can run the below command.

make test-all TESTS=test/coverage/test_coverage.rb
Run options: "--ruby=./miniruby -I./lib -I. -I.ext/common  ./tool/runruby.rb --extout=.ext  -- --disable-gems" --excludes-dir=./test/excludes --name=!/memory_leak/

# Running tests:

Finished tests in 1.580204s, 12.0238 tests/s, 74.6739 assertions/s.
19 tests, 118 assertions, 0 failures, 0 errors, 0 skips

ruby -v: ruby 2.6.0dev (2018-01-13 trunk 61811) [x86_64-darwin15]

Running Specs

Below we can see how to run a single specific spec file

make test-spec MSPECOPT=spec/ruby/library/coverage/start_spec.rb
generating x86_64-darwin15-fake.rb
x86_64-darwin15-fake.rb updated
$ /Users/danmayer/projects/ruby/miniruby -I/Users/danmayer/projects/ruby/lib /Users/danmayer/projects/ruby/tool/runruby.rb --archdir=/Users/danmayer/projects/ruby --extout=.ext -- /Users/danmayer/projects/ruby/spec/mspec/bin/mspec-run -B ./spec/default.mspec spec/ruby/library/coverage/start_spec.rb
ruby 2.6.0dev (2018-01-13 trunk 61811) [x86_64-darwin15]
[\ | ==================100%================== | 00:00:00]      0F      0E

Finished in 0.002753 seconds

1 file, 0 examples, 0 expectations, 0 failures, 0 errors, 0 tagged
comments

January Software Links 03 February 2018

Some of my favorite links from January. Also, I will use this month to highlight a group of folks who have been sharing advice and helping me grow for a number of years now. Thanks!

The above folks in a mentoring group recommend good books, bounce ideas off each other, and help folks prep for big talks, events, or projects. Thanks!

Software Development

Data

Ruby

Tech Management

Random

Random Links

Links by wsyperek

comments

December Software Links 31 December 2017

Some of my favorite links from December. If you have any good links I missed pass them my way.

continuing my trend of having something from @davetron5000 each month, and this month I have two ;)

Software Development

Ruby

DevOps

Tech Management

Random

Random Links

Links by wsyperek

comments

On Tech Challenges 18 December 2017

Coding Challenge

The company I am with, Offgrid-Electric, has evolved our hiring process over time to try to ensure we can find a diverse and strong distributed team. There are many interesting processes related to hiring a distributed team, but I will quickly focus on the coding challenge, technical challenge, or whatever folks are calling it these days.

Job Challenge

image by FotografieLink

Offer Challenge Options

This post is kicked off by the thread below.

Folks followed up asking for more details on other challenge options we provide and why, which I will try to breakdown below.

What is the point?

First off why have a coding exercise in person, take-home, or other? The goal is to allow a candidate to demonstrate skills beyond being great to talk with during interviews. That they can back up the conversation with problem-solving skills that match the team’s expectations. There are far too many posts and stories joking about how few developers can code, which I will skip over, but often a team wants a way to help ensure that a candidate has skills that will make them successful if they join. At OGE we try to allow for the widest possible options to prove out that a candidate would be technically qualified or the position.

Tech Challenges Options

We offered a few standard options and have added more and evolved our challenges over time.

Take Home Challenge: We have someone on our team develop a challenge for any job description we are hiring for. The challenge is prepared before we even post a job opening. In general, we have someone on the team develop the challenge and complete it themselves to ensure they fully understand the challenge and have a good estimate of the time required to complete it (generally 2-4 hrs). This falls somewhere into the category of building a small application that does X, Y, and Z given this sample data set. Given folks likely have a current job we give plenty of time to work on the challenge and include instructions for how to submit the challenge and things we expect to see.

Pair Programming: We had some folks talk to us that enjoy pair programming and find it a good way to understand the way our current team works and thinks. We offer to pair on the take-home challenge and work on it with the candidate at a scheduled time, or to work on some of the code we are currently working on, or to pair on some code that the candidate has recently been working on. Some folks are very comfortable with this kind of exercise while others get very nervous pairing with someone they are just getting to know. Some folks have paired a lot in the past, or it might be a fairly new experience for them. Unless your team practices 100% pair programming, I believe you should offer some alternatives to just pairing. I like having a take-home challenge that can also be offered as a pairing exercise.

Open Source Work: This is a great option for folks that already have a lot of publicly available code they are proud of and showcases their skills. There is no reason to make someone spend extra hours of their time when you could have them walk you through code they are passionate about and have already been working on. I have enjoyed learning about some candidates projects even if it wasn’t a great fit and the enthusiasm for something they have recently worked on in their own time shows through. It is important to have other options beyond just open source. While this is a great alternative, it can’t be the primary or expected way to check off the technical challenge. You can find more detailed reasoning about this on various diversity hiring posts, but not everyone has the same privilege to spend extra time outside of work on open source, some jobs don’t allow it, it isn’t everyone’s cup of tea.

Technical Questioning: While I prefer to do something with code like the options listed above, sometimes that isn’t the best fit for whatever reason. In these cases, we have done some technical white boarding type interviews over video chat. In my interview, at OGE, I walked through how to split out a monolith application into smaller component applications and discussed the kind of DevOps you need to support such transitions. This format has also worked well for QA interviews. I try to avoid trick questions / brain teasers. Asking data modeling questions tends to work pretty well over a whiteboard for an example of good technical questions.

Choose your own Adventure

Taking this even further, given our only goal with this part of the interview process is to come away with some confidence that the person is technically capable in a set of skills… I often ask the candidate after presenting our standard challenge options listed above if that have any other way they would like to prove out technical skills. I will list some things candidates have suggested or done before.

Technical Writing / Educational Materials: We have had some folks apply that have created online materials for courses. Sharing video series that teach programming concepts, blog posts detailing how to use some technology, or videos of talks given at a conference covering technically relevant material.

School Projects / Papers: If you are talking to someone recently coming out of university they might have some great projects they could share with you. If it is a group project just get into specifics about what pieces they directly contributed. We recently had a candidate submit their Ph.D. thesis as a way to confirm their technical skill.

Code Reading / Walkthrough: A few candidates that didn’t have open source code but as consultants had learned to quickly look at projects and distill how they worked. In this case, they were also curious to see how our systems worked. After some discussion, we walked through sections of our companies source code with the candidate reading the code and explaining what it did and the recommendations they would have to improve that section of code. While this is a bit more challenging on the interviewer’s side, it can give candidates a great picture of the kind of code and the quality of the project they will be getting involved in. If the person can quickly jump in and absorb parts of the project’s domain and explain it back to you, it can give you the confidence you need to move forward.

Comfortable Candidates Can Share Their Skills

In the end, it comes down to just making sure you set a candidate up to show you their best work. You don’t want to setup a situation that will have a great candidate so nervous they don’t show what they are capable of. Being a globally distributed team, in the end, I don’t expect all our team to work the same way, so I wouldn’t expect all candidates to succeed in the same style of challenges. You can always find a developer that loves to pair or hates it, or gets very nervous working out a problem on a whiteboard or could lecture in front of a whiteboard for hours on end. All of that is fine, let em shine.

comments

November Software Links 02 December 2017

Some of my favorite links from November. If you have any good links I missed pass them my way.

Software Development


intentionally and proactively providing an extra-normal level of support and manual help to users in order to learn about the barriers people are hitting

service and support driven development

Data

Ruby

Devops

Tech Management

Random

Random Links

Links by wsyperek

comments
Dan Mayer Profile Pic
Welcome to Dan Mayer's development blog. I primary write about Ruby development, distributed teams, and dev/PM process. The archives go back to my first CS classes during college when I was first learning programming. I contribute to a few OSS projects and often work on my own projects, You can find my code on github.

Twitter @danmayer

Github @danmayer