Personalvermittler

iPhone_no_caller_ID_640Wir sind regelmässig auf der Suche nach neuen Mitarbeitern. Genau so regelmässig werden wir von Vermittlern kontaktiert.

Per Telefon und Mail erhalten wir immer wieder CVs der tollsten und besten Entwickler angeboten. Auf den freundlichen Hinweis, dass wir nicht mit Personalvermittlern zusammenarbeiten wird meist leicht verwirrt mit “Aber warum denn nicht?” geantwortet. Schliesslich ist der Vermittler professionell und vermittelt ausschliesslich im IT-Bereich Personal. Ja die anderen Vermittler, das kann er ja noch verstehen, die sind ja eher rückständig und haben sowieso nur faule Eier im Angebot. Aber er selbst… nur Mitarbeiter welche menschlich und fachlich sowas von zu uns passen…

Du bist selbst Vermittler und findest, dass ich pauschale Aussagen mache und, dass bei Dir alles besser ist? Ist bis jetzt leider nicht die Erfahrung die ich als Arbeitgeber gemacht habe.

Warum wir nicht mit Vermittlern arbeiten?

Eigentlich einfach: Wir können es besser.

Wir haben über die letzten Jahre genug Bewerbungen erhalten, Interviews geführt und Arbeitsproben angeschaut. Wir haben unsere eigene Methode entwickelt, wir führen Interviews, wir reden mit den Kandidaten. Wir stellen sicher, dass sie zu uns passen. Die Resultate sprechen für sich, wir haben eine tiefe Fluktuation und gute Mitarbeiter.

Das alles liesse sich auch von externen Vermittlern machen und würde uns sogar Zeit sparen. Aber die Qualität der Dienstleistung “Personalvermittlung” passt ganz einfach nicht:

Vermittler verstehen nicht was wir machen

Sie lesen “Entwickler für Webapplikationen” und denken “Programmierer”. Und schicken uns das Profil eines Kandidaten welcher “Embedded Systems” entwickelt.
Sie lesen “Ruby on Rails” und denken “Programmiersprache”. Und schicken uns das Profil eines Kandidaten welcher Python/Django entwickeln will.

Wenn ich mich nicht auf die Vorselektion durch einen Vermittler verlassen kann, dann nimmt er mit keine Arbeit ab.

Vermittler verstehen nicht wie wir arbeiten

Woher auch. Sie beschränken ihre Kommunikation darauf uns CVs zu schicken. Noch nie hat ein Recruiter bei uns angerufen und gefragt “Wie arbeitet ihr denn?” oder “Was muss ein Kandidat denn mitbringen?” oder auch “Was bietet Ihr denn einem Mitarbeiter an?”
Das soll jetzt kein Aufruf sein, wir haben mit dem Thema abgeschlossen. Nach meinem Verständnis muss der Anbieter zuerst mit dem Kunden sprechen um genau zu verstehen, was dieser denn will und wie man ihm helfen kann.

Vermittler kosten viel Geld

Je nach Agentur werden 20 – 35% eines Jahresgehaltes für eine erfolgreiche Vermittlung veranschlagt. Wir reden also von Beträgen von 15’000 CHF aufwärts, je nach Pensum und Position.
Dafür erwarte ich eine Leistung die weit über das verschicken eines Lebenslaufes per E-Mail oder ein paar Telefonanrufe mit unterdrückter Rufnummer hinausgeht.
Was passiert wenn der Vertrag mit einem Kandidaten nach kurzer Zeit wieder aufgelöst wird? Hier gibt es je nach Firma verschiedene Modelle. Oft gibt es eine zeitlich gestaffelte Rückzahlung.
Also z.B. nach 2 Wochen 80%, nach 4 Wochen 60% u.s.w. Meistens gibt es spätestens nach 3 Monaten nichts mehr zurück. Also dann, wenn die Probezeit vorbei ist.
Dies alles deutet nicht auf Vertrauen in die eigene Arbeit hin. Wenn der Kandidat doch so gut passt und extra für meine Stelle ausgesucht wurde, dann darf hier schon etwas mehr erwartet werden.

Vermittler versuchen bei uns Personal abzuwerben

Das ist kein grundsätzliches Problem für mich. Wenn ein Mitarbeiter gehen möchte, dann kann er, darf er, soll er gehen.
Wir haben talentierte Entwickler und diese sind gesucht. Vermittler fernzuhalten gehört nicht zu den Strategien um die Fluktuation tief zu halten.

Wir versuchen unsere Mitarbeiter zu halten und geben uns Mühe ein angenehmes Arbeitsumfeld zu schaffen. Wir sind eine kleine Firma und haben weniger Möglichkeiten wie eine Bank oder IBM oder gar Google. Aber bei uns gibt es spannende Projekte, Freiheiten und die Möglichkeit ein Projekt von A-Z zu begleiten.

Aber wenn der gleiche Recruiter am Morgen versucht jemanden abzuwerben und am Nachmittag einen Entwickler bei uns zu platzieren, dann kann es mit der Moral nicht weit sein.

Vermittler lügen uns an

Und zwar knallhart und direkt. “Herr XY hat gesagt wir sollen uns melden wenn wir einen Kandidaten haben”. Dumm nur, dass Herr XY bereits am Telefon ist. Und dies natürlich nie gesagt hat. Ein paar andere Beispiele?

    • Es wird erzählt, dass Kandidaten exklusiv repräsentiert werden, aber die Kandidaten wissen nichts davon.
    • Einer hat grad sein Handy nicht dabei und darum die Telefonnummer von Mitarbeiter X nicht zur Hand und hätte doch gerne die private Nummer.
    • Ein Anderer ist ein Freund und ruft von Zuhause an (und im Hintergrund tönt es wie es halt so in einem Callcenter tönt).
    • Der gemeinsame Bekannte Z hat empfohlen, dass wir mit dem Vermittler zusammenarbeiten sollen.

Wie soll das bitte funktionieren? Wie soll ich mit jemanden zusammenarbeiten der mich einfach mal direkt anlügt?

Vermittler lügen die Kandidaten an

Da werden Stellen ausgeschrieben die es so nicht gibt, damit man CVs zugeschickt bekommt. Es wird von Mandaten erzählt die nie erteilt wurden. Die guten Connections zum potentiellen Arbeitgeber nicht zu vergessen.

Vermittler arbeiten unsauber

CVs werden ungefragt an Firmen weitergegeben. Nicht anonymisiert, oder so, dass eine kurze Suche gleich die Personalien rausspuckt.

Ich kenne einen Fall wo ein Vermittler einen Lebenslauf eines Bewerbers ungefragt an eine Firma weitergeleitet hat. Die Firma war unglücklicherweise Kunde des aktuellen Arbeitgebers. Der Kunde hat prompt beim aktuellen Arbeitgeber angerufen worauf diesem kurzfristig der Blutdruck in die Höhe schnellte…

Es gehört für mich zum 1×1, dass ein Kandidat gefragt wird: “Hey ist es OK, wenn ich deinen Lebenslauf an die Firma X weitergebe?”

Gleichzeitig möchte ich nicht einfach so ein Profil zugeschickt bekommen. Meistens erkenne ich die Kandidaten weil ich die Netzwerke aktiv durchforste. Und dann findet der Vermittler natürlich, er habe ein Anrecht auf eine Entschädigung weil ja SEIN Kandidat kontaktiert wurde. Alles schon gehabt – der Fall konnte erst nach einem freundlichen Schreiben eines Anwaltes geklärt werden.

Kandidaten sollen wirklich daran interessiert sein bei uns zu arbeiten

Und darum sollten sie auch den Aufwand nicht scheuen selber nach offenen Stellen zu suchen, etwas über die Firma in Erfahrung zu bringen und sich dann, bei Gefallen, bei uns zu melden. Das ist etwas schwerer für Bewerber aus dem Ausland, aber selbst von da ist es möglich. Aber wer im Raum Zürich, ja sogar in der ganzen Schweiz einen Ruby-Job sucht, der sollte uns finden können und nicht den Umweg über den Vermittler nehmen.

Fazit

Wenn die einzige Leistung eines Vermittlers darin besteht CVs auf dubiose Art abzufischen und danach wieder zu verteilen, dann generiert das keinen Mehrwert für mich. In einem Bereich wo mit einem Abschluss ein 5-Stelliger Umsatz gemacht werden kann, werden schnell mal schwarze Schafe angelockt. Besonders wenn man sich mit Xing und LinkedIn auf einfache Art und Weise durch zig Profile wühlen kann.
Vielleicht gibt es seriöse Vermittler. Aber auf dem Gebiet sind mir noch nicht viele begegnet.

Und so heisst es bei uns weiterhin: “Dossiers welche von Vermittlern zugeschickt werden können wir leider nicht berücksichtigen”.

Ruby API doc and Module

The Ruby API doc is a great source for information about my programming language of choice. Even after years of writing ruby code i learn new tricks and features.
Lately i’ve been looking into the Module class in more detail.

I did not know that there is a callback for methods being added to a class. Not that i missed them much or that i even know what i could use them for. Similar exists for removal of methods.

class Foo
 def self.method_added(method)
   puts method
 end

 def hello_world
 end
end

# => "hello_world"

Because there is also a callback for methods that are undef’d (no documentation for this method though) i started to wonder what the difference between removing and undefining a method is. Consider the following classes:

class Base
 def hello_world
   puts "Hello World from #{self.class.name}"
 end

 def self.method_removed(name)
   puts "removed #{name} from #{self.class.name}"
 end

 def self.method_undefined(name)
   puts "undefined #{name} from #{self.class.name}"
 end
end

class Undefined < Base
 def hello_world
   puts "Hello World from #{self.class.name}"
 end

 undef_method(:hello_world)
end

class Removed < Base
 def hello_world
   puts "Hello World from #{self.class.name}"
 end

 remove_method(:hello_world)
end

If you run the code there will be some output from the callbacks:

undefined hello_world from Class
removed hello_world from Class

But the interesting part starts when you call those methods:

Removed.new.hello_world
# => Hello World from Removed

Undefined.new.hello_world
# => undefined method `hello_world' for #<Undefined:0x007f8dd488a8d8> (NoMethodError)

undef_method prevents the class from responding to a method, even if it is present in a superclass or mixed in module. remove_method only removes it from the current class hence it will still respond to the call if the method is defined in superclass or mixed in.

Something that i’ve seen in other people’s source code already but don’t use myself: the ability to pass a list of Strings/Symbols to the visibility modifiers such as private, public and protected:

class Foo
 def a_method
 end
 private(:a_method)
end

Foo.new.a_method

# => private method `a_method' called for #<Foo:0x007fb169861c90> (NoMethodError)

Note that those visibility modifiers are methods and not part of the language syntax. This is different from other languages like Java where public/private/protected are language keywords (and no modifier is also supported and leads to default visibility).

Actually i prefer the Java syntax over the ruby one: having the visibility part of the method signature makes it easy to spot what visibility a method has. Especially for long classes this might be difficult in Ruby.
It is actually possible to have a similar style in ruby. Ruby allows to write multiple statements on one line as long as they are separated by a semicolon:

class Foo
 private; def hello_world
   puts "hello world"
 end
end

Looks awkward and modifies the visibility for all following methods as well.

For newer Rubies (2.1+) you can omit the semicolon as def is not void anymore but returns a Symbol (the method name):

class Foo
 private def hello_world
   puts "hello world"
 end
end

(Thanks to Thomas Ritter for the hint).

Now lets look at how you would make a private class method:

class Foo
  private
  def self.hello_world
    puts "hello World"
  end
end

You would expect hello_world to be private, right? Not exactly: you can still call it:

Foo.hello_world
# => hello_world

So why is that? Because to change the visibility of class methods you need to use private_class_method like so:

class Foo
  def self.hello_world
    puts "hello World"
  end
  private_class_method :hello_world
end

Note that confusingly private_class_method does not set the visibility for class methods following that call like private does. You need to pass the method name as an argument!

So i stick to grouping methods by visibility and write small classes to make sure i don’t lose track of what visibility the methods are in.

Learned something new today? Then go pick a class of ruby core and read up on it on the API doc. Chances are you are learning something new.

Rake Tasks With Parameters

Rake tasks are a convenient method to automate repeating tasks and also make them available via the command line.
Oftentimes these tasks can be executed without any user input. Think of a built-in task like “db:migrate” — it does not take any arguments. There’s other tasks that in fact take arguments. Usually, they work like this: rake the_namespace:the_task[arg1,arg2].

If you look for a solution to rake tasks with arguments, you often find this code snippet:


namespace :utils do

  task :my_task, [:arg1, :arg2] do |t, args|
    puts "Args were: #{args}"
  end

end

This code snippet, however, does not load your Rails environment. So you cannot load any models for example.

A solution to this problem looks like this:


namespace :utils do

  desc 'Unlocks this user. Usage: utils:unlock_user USER=42'
  task :unlock_user => :environment do |t, args|
    user_id = ENV['USER'].to_i
    puts "Loading user with id = #{user_id}"

    user = User.find(user_id)
    user.unlock!
  end

end

You call this rake task with rake utils:unlock_user USER=42. By specifying USER=42 you load this argument into the environment variables.

There is, however, a more standard way of implementing this.


namespace :utils do

  desc 'Unlocks this user. Usage: utils:unlock_user[42] for the user ID 42'
  task :unlock_user, [:user_id] => :environment do |task, args|
    user_id = args.user_id
    puts "Loading user with id = #{user_id}"

    user = User.find(user_id)
    user.unlock!
  end

end

There we go, we now have a rake task with arguments in brackets. If you want to have more arguments, you simply add them to the arguments list after the task name and retrieve it in the args object by its name.

Which variant of rake task you prefer is up to you. The first one with the explicit environment variable is probably easier to read, the second variant is more in line with standard rake.

Returning Enumerator unless block_given?

The Enumerable module gives you methods to search, iterate, traverse and sort elements of a collection. All you need to to is to implement each and include the mixin.

class NameList
  include Enumerable

  def initialize(*names)
    @names = names
  end

  def each
    @names.each { |name| yield(name) }
  end
end

list = NameList.new('Kaiser Chiefs', 'Muse', 'Beck')

list.each_with_index do |name, index|
  puts "#{index + 1}: #{name}"
end

# => 1: Kaiser Chiefs
# => 2: Muse
# => 3: Beck

So by defining each and including Enumerable we got an impressive list of methods that we can call on our NameList instance. But having all those methods added does not feel right. Usually you will use one or two of them. Why clutter the interface by adding 50+ methods that you’ll never use? There is an easy solution for this:

class NameList
  def initialize(*names)
    @names = names
  end

  def each
    return @names.to_enum(:each) unless block_given?
    @names.each { |name| yield(name) }
  end
end

list = NameList.new('Kaiser Chiefs', 'Muse', 'Beck')

list.each do |name|
  puts name
end
# => Kaiser Chiefs
# => Muse
# => Beck

list.each.each_with_index do |name, index|
  puts "#{index + 1}: #{name}"
end
# => 1: Kaiser Chiefs
# => 2: Muse
# => 3: Beck

Note that each now returns the Enumerator on which you can call each_with_index (or any of the other methods) unless a block is given. So you can even call it like this:

puts list.each.to_a.size
# => 3

By returning an Enumerator when no block is given one can chain enumerator methods. Ever wanted to do a each_with_index on a hash? There you go:

points = {mushroom: 10, coin: 12, flower: 4}
points.each.each_with_index do |key_value_pair, index|
  puts "#{index + 1}: #{key_value_pair}"
end

# => 1: [:mushroom, 10]
# => 2: [:coin, 12]
# => 3: [:flower, 4]

Ruby and the double splat operator

If you have been programming ruby for a while then you have seen the splat operator. It can be used to define methods that accept a variable length argument list like so:

def single_splat(an_argument, *rest)
 puts "#{rest.size} additional argument(s)"
end

single_splat('howdy')
#=> 0 additional argument(s)

single_splat('howdy', :foo)
#=> 1 additional argument(s)

single_splat('howdy', :foo, :bar, :baz)
#=> 3 additional argument(s)

But also to “unwrap” values from an array and pass them as single arguments:

def unwrapped(a, b, c)
 puts "#{a} / #{b} / #{c}"
end

data = [1, 2, 3]

unwrapped(*data)
# => 1 / 2 / 3

unwrapped(data)
#=> wrong number of arguments (1 for 3) (ArgumentError)

But behold can use the splat operator also to coerce values into arrays:

coerced = *"Hello World"
p coerced
# => ["Hello World"]

coerced = *nil
p coerced
# => []

coerced = *[1, 2, 3]
p coerced
# => [1, 2, 3]

And of course to deconstruct arrays:

data = [1, 2, 3, 4]

first, *rest = data
puts "#{first}, #{rest}"
# => 1, [2, 3, 4]
*list, last = data
puts "#{list}, #{last}"
# => [1, 2, 3], 4

first, *center, last = data
puts "#{first}, #{center}, #{last}"
# => 1, [2, 3], 4

first, second, *center, third, fourth = data
puts "#{first}, #{second}, #{center}, #{third}, #{fourth}"
# => 1, 2, [], 3, 4

But now back to the double splat operator. It has been added to Ruby in version 2.0 and behaves similarly to the single splat operator but for hashes in argument lists:

def double_splat(**hash)
 p hash
end

double_splat()
# => {}

double_splat(a: 1)
# => {:a => 1}

double_splat(a: 1, b: 2)
# => {:a => 1, :b => 2}

double_splat('a non hash argument')
# => `double_splat': wrong number of arguments (1 for 0) (ArgumentError)
# (The message for the case where I pass in a non-hash argument is not very helpful i'd say)

“What!” i can hear you shout. Where is the difference to a standard argument. In the use case as shown above it is pretty much the same. But you would be able to pass in nil values or non hash values, so more checks would be required:

def standard_argument(hash = {})
 puts hash
end

standard_argument()
# => {}

standard_argument(nil)
# =>

Now if we move this to a more realistic use case, consider a method taking a variable list of arguments AND some options:

def extracted_options(*names, **options)
 puts "#{names} / #{options}"
end

extracted_options()
# => [] / {}

extracted_options('pascal', 'lukas', color: '#123456', offset: 3, other_option: :foo)
# => ["pascal", "lukas"] / {:color=>"#123456", :offset=>3, :other_option=>:foo}

Ruby on Rails developers might know this pattern already. It is used in various parts of the framework. It is so common that the functionality has been defined in extract_options!

Handling errors in Ruby on Rails

Rails offers multiple ways to deal with exceptions and depending on what you want to achieve you can pick either of those solutions. Let me walk you through the possibilities.

begin/rescue block

begin/rescue blocks are the standard ruby mechanism to deal with exceptions. It might look like this:

begin
  do_something
rescue
  handle_exception
end

This works nice for exceptions that might happen in your code. But what if you want to rescue every occurrence of a specific exception, say a NoPermissionError which might be raised from your security layer? Clearly you do not want to add a begin/rescue block in all your actions just to render an error message, right?

Around filter

An around filter could be used to catch all those exceptions of a given class. Honestly I haven’t used a before filter for this, this idea came to my mind when writing this blog post.

class ApplicationController < ActionController::Base
  around_action :handle_exceptions

  private
  def handle_exceptions
    begin
      yield
    rescue NoPermissionError
      redirect_to 'permission_error'
    end
  end
end

rescue_from

rescue_from gives you the same possibilities as the around filter. It’s just shorter and easier to read and if the framework offers a convenient way, then why not use it. There are multiple ways to define a handler for an exception, for a short and sweet handler I prefer the block syntax:

class ApplicationController < ActionController::Base
 rescue_from 'NoPermissionError' do |exception|
   redirect_to 'permission_error'
 end
end

exceptions_app

There is an additional feature (added in Rails 3.2) that allows to handle exceptions. You can specify an exceptions_app which is used to handle errors. You can use your own Rails app for this:

config.exceptions_app = self.routes

If you do so, then your routing must be configured to match error codes like so:

match '/404', to: 'exceptions#handle_404'
...

Alternatively you can specify a lambda which receives the whole Rack env:

config.exceptions_app = lambda do |env|
  # do something
end

Do you wonder how you can call an arbitrary action when you have the env? It’s pretty easy:

action = ExceptionsController.action(:render_error)
action.call(env)

In any case you want to set following configuration for exceptions_app to be used:

Rails.application.config.consider_all_requests_local = false
Rails.application.config.action_dispatch.show_exceptions = true

But where is the exception you ask? It is stored in the Rack env:

env[<span class="pl-s1"><span class="pl-pds">'</span>action_dispatch.exception<span class="pl-pds">'</span></span>]

And as a bonus: here is how you can determine an appropriate status code for an exception:

wrapper = <span class="pl-s3">ActionDispatch</span>::<span class="pl-s3">ExceptionWrapper</span>.<span class="pl-k">new</span>(env, exception)
wrapper.status_code

There is more information you can extract using the exception wrapper. Best you look it up in the API description.

Most of this code can be seen in action in our infrastructure gem which we use to add error pages to apps we build.