The Simplificator blog

You are reading articles by Simplificator, a Swiss-based custom software development agency. Here we write about the problems we solve and how we work together.

How to kill processes on Windows using Ruby

In order to terminate a process in Ruby you can use the kill method in the of the Process class in the following way:

pid = 1234
Process.kill("TERM", pid)

If you are using Ruby on Windows you have probably already noticed that Process.kill does not work correctly.

There are two problems with it:

  1. It does not recognize any signal except KILL;
  2. When it kills a process with Process.kill("KILL", pid) the process incorrectly returns status 0 (success).

Here is an example:

# On Windows:
irb(main):002:0> Process.kill("TERM", 1234)
Errno::EINVAL: Invalid argument

# On Linux:
irb(main):003:0> Process.kill("TERM", 686868)
Errno::ESRCH: No such process

Windows complains that TERM is an invalid argument, although Signal.list includes TERM:

irb(main):003:0> Signal.list
=> {"EXIT"=>0, "INT"=>2, "ILL"=>4, "ABRT"=>22, "FPE"=>8, "KILL"=>9, "SEGV"=>11, "TERM"=>15}

You might think Process.kill(15, PID) works but it fails with the same error.

The KILL signal however works:

irb(main):004:0> Process.kill("KILL", 768)
=> 1

The questions is: does it work correctly?

Let's run some tests. I ran the following script for testing:

Open an irb instance and run:

command = "tracert www.google.com"
exitstatus = nil
Open3::popen3(command) do |stdin, stdout, stderr, wait_thread|
puts "PID: #{wait_thread.pid}" # ===> this will give you the PID.
status = wait_thread.value
puts "============"
puts "termsig=#{status.termsig.inspect}"
puts "success?=#{status.success?.inspect}"
puts "stopsig=#{status.stopsig.inspect}"
puts "stopped?=#{status.stopped?.inspect}"
puts "signaled?=#{status.signaled?.inspect}"
puts "exitstatus=#{status.exitstatus.inspect}"
puts "exited?=#{status.exited?.inspect}"
puts "status.inspect=#{status.inspect}"
exitstatus = status.exitstatus
puts "============"
end
puts exitstatus.inspect

From a different irb session run the following:

pid = 'XXX' # printed in the code above
Process.kill("KILL", pid)

Here are the results I got:

# KILL Force Windows with Process.kill("KILL", pid)
# PID: 2816
# ============
# termsig=nil
# success?=true <======= wrong on Windows, it was a force kill
# stopsig=nil
# stopped?=false
# signaled?=false
# exitstatus=0 <======== wrong on Windows, it was a force kill
# exited?=true
# status.inspect=#<Process::Status: pid 2816 exit 0>
# ============

What is even worse is that if you run the command again and wait until it finishes (thus no Process.kill), the output is exactly the same.

# Success Windows
# PID: 4860
# ============
# termsig=nil
# success?=true <======== correct
# stopsig=nil
# stopped?=false
# signaled?=false
# exitstatus=0 <======== correct
# exited?=true
# status.inspect=#<Process::Status: pid 4860 exit 0>
# ============

This means we cannot rely on Process.kill("KILL", PID) on Windows to stop a process. Please correct me if I am wrong but to me the two outputs above look the same.

I performed the same test (only changed the command tracert to traceroute) on OSX and here are the results:

Without Process.kill, the command finishes successfully:

# Success OSX
# ============
# termsig=nil
# success?=true <========= correct
# stopsig=nil
# stopped?=false
# signaled?=false
# exitstatus=0 <========= correct
# exited?=true
# status.inspect=#<Process::Status: pid 54466 exit 0>
# ============

With Process.kill, the command exits with a status code different than 0:

# KILL force on OSX
# ============
# termsig=9 <========= correct
# success?=nil <========= better
# stopsig=nil
# stopped?=false
# signaled?=true <========= looks good
# exitstatus=nil
# exited?=false
# status.inspect=#<Process::Status: pid 54523 SIGKILL (signal 9)>
# ============

Now the question remains: how do I kill a process on Windows?

I found an easy way using the taskkill command. Please check if your version of Windows is included in the link above.

system("taskkill /pid #{pid}")      # graceful stop, will return true / false
system("taskkill /f /pid #{pid}") # force stop, will return true / false

In case you are wondering how the output of the test script looks on Windows with taskkill /f here it is:

# KILL Force Windows with taskkill /f /pid PID
# PID: 4740
# ============
# termsig=nil
# success?=false <======= correct!
# stopsig=nil
# stopped?=false
# signaled?=false
# exitstatus=1 <======== correct!
# exited?=true
# status.inspect=#<Process::Status: pid 4740 exit 1>
# ============

Happy hacking!

Feature testing mobile variants

For a project, we wanted to write a feature spec for the mobile variant of the site. Instinctively, the first thing I did was google. I found nothing. The next thing I did was think. I came up with this, which worked:

require 'rails_helper'

feature 'Mobile variant' do
before do
allow_any_instance_of(ActionDispatch::Request).to receive(:variant).and_return([:mobile])
end

scenario 'Look at customer information' do
# your test here!
end
end

Happy testing!

Love what you do

You're a professional. Your work is part of who you are. Connect the work with your motivation, and find out what makes you tick. If you can be authentic in your work, do things the right way, you'll get a feeling of achievement, and of being one with your work. This is important because it's the only way to employ the unconscious part of your brain, your intuition. This part helps you be great - if you have to think about every step you do you slow yourself down. If it doesn't feel right, think about it and get the roadblocks away. You know you're doing it right when you truly love what you do.love_what_you_do.jpg

Xcode 7 and the CircleCI

We're using CircleCI for one of our iOS projects and recently we migrated to Xcode 7. However, since the migration we noticed that the builds on CircleCI started to fail. Even worse, all tests were passing locally in Xcode.

The error we got on CircleCi was:

Unable to read build settings for target 'MyProjectTests'. It's likely that the scheme references a non-existent target.

... (output supressed)

STDERR: xcodebuild: error: The test action requires that the name of a scheme in the project is provided using the "-scheme" option. The "-list" option can be used to find the names of the schemes in the project.

We're using the Facebook's xctool to run the build and the tests on the CI. The command looks like:

xctool \
 -reporter pretty \
 -reporter junit:~/Desktop/xcode/results.xml \
 -reporter plain:~/Desktop/xctool.log \
 CODE_SIGNING_REQUIRED=NO \
 CODE_SIGN_IDENTITY= \
 PROVISIONING_PROFILE= \
 -destination 'platform=iOS Simulator,name=iPhone 6,OS=9.0' \
 -sdk iphonesimulator \
 -project 'MyProject.xcodeproj' \
 -scheme "MyProject" \
 build \
 build-tests \
 run-tests

How do you run it on your Mac? First make sure you install xctool via homebrew.

brew update
brew install xctool

Then run the xctool command above and see what happens. In our case everything went well locally, the tool succeeded to build and the tests were green as expected.

Still, the CircleCI was red. We noticed that there was a different version of xctool installed on the CI. The version the CI was using was 0.2.2 and the version installed via homebrew on the local machines reported 0.2.6.

The fix: add a dependency in the circle.yml to preinstall the latest version of xctool.

Our circle.yml looks like below and the build is green. Happy testing!

machine:
xcode:
version: "7.0"
checkout:
post:
- git submodule sync
- git submodule update --init
dependencies:
pre:
- brew uninstall xctool && brew install --HEAD xctool
test:
override:
- xctool
-reporter pretty
-reporter junit:$CIRCLE_TEST_REPORTS/xcode/results.xml
-reporter plain:$CIRCLE_ARTIFACTS/xctool.log
CODE_SIGNING_REQUIRED=NO
CODE_SIGN_IDENTITY=
PROVISIONING_PROFILE=
-destination 'platform=iOS Simulator,name=iPhone 6,OS=9.0'
-sdk iphonesimulator
-project 'MyProject.xcodeproj'
-scheme "MyProject"
build build-tests run-tests

Simplification Conference

Zum ersten Mal findet diesen November unsere Simplification Conference statt. Professioneller Input paart sich hier mit den digitalen Ideen der Teilnehmer. Simplificator stellt sein Know-how einen Nachmittag lang kostenlos zur Verfügung für Themen wie Web-Apps, Mobile-Apps, Code Qualität, Rails, UI-/UX-Design, Testing, Integration, Simplification, Usability und Workflow.

Hier geht's zur Einladung mit weiteren Informationen.

Gastbeitrag Personalvermittler

Im Blogeintrag „Personalvermittler“ teilt Pascal Betz seine Erfahrungen betreffend Personalvermittler.

Danke, dass Pascal mir, aus Sicht eines Personalvermittlers, die Chance gibt auf seinen Post zu antworten und allenfalls ein anderes Licht auf Personalvermittler zu werfen.

Source: findaphoto.com

Der Vermittlermarkt ist riesig und hart umkämpft

Viele (oft bei grösseren Agenturen angestellte) Personalvermittler wagen den Schritt in die Selbständigkeit und überlegen sich, dass sie mit zwei Vermittlungen pro Monat leicht mehrere zehntausend Franken verdienen können. Dies ist natürlich attraktiver als ein monatliches Gehalt in einer Anstellung zu bekommen. So entstehen unzählige kleine Agenturen; momentan gibt es in der Schweiz ca. 4‘500 Personalvermittler.

Die meisten Grossunternehmen haben mittlerweile Preferred Supplier Listen und einen strategischen Einkauf eingeführt, sowie Compliance-Richtlinien, welche es kleinen Agenturen nicht mehr erlauben mit den Grossen zusammenzuarbeiten bzw. die Zusammenarbeit sehr reglementieren. Dadurch müssen sich die kleinen Personalagenturen auf KMU's stürzen. Vermitteln um jeden Preis heisst die Devise, da das Honorar ihr Lohn ist. Um jeden Preis heisst dabei auch, dass gesetzliche Regelungen und ein korrektes Businessverhalten ausser Acht gelassen werden. Genau dies schadet dann dem Ansehen der gesamten Branche.

Folgende Punkte sind gesetzlich geregelt:

Die Ausschreibung einer Stelle muss den Tatsachen entsprechen

Wie Pascal in seinem Blogeintrag schreibt, verstehen Vermittler nicht, was die gesuchte Person an Erfahrungen und Skills mitbringen soll. Ausserdem kennen die Vermittler das Unternehmen nicht. Für ein seriöses „Matching“ zwischen Bewerber und Unternehmen ist es essenziell, dass der Personalvermittler den Bewerber und das Unternehmen kennenlernt und beiden Parteien die „richtigen“ Fragen stellt. Für die Sicherstellung der Qualität des sogenannten Qualifizierens des Kandidaten benötigt der Personalvermittler ausgebildetes Personal, welches auch auf bestimmte Branchen spezialisiert ist (z.B. IT, Pharma, Banken etc.) und den Markt innerhalb seiner Branche kennt.

Fiktive Stellenangebote müssen gekennzeichnet werden, ansonsten sind sie nicht zulässig

Personalagenturen ködern Bewerber mit fiktiven Angeboten, um Ihren Kandidatenpool aufzubauen und bei Stellenausschreibungen Unternehmen diese Kandidaten schnell anbieten zu können. Diese Art von Sourcing ist für Bewerber sehr unbefriedigend, da Sie sich auf eine spezifische Stelle bewerben, das Bewerbungsdossier zusammenstellen und dann maximal in der Datenbank einer Agentur landen.

Solche Angebote sind nur zulässig, wenn dies klar ersichtlich ist.

Datenschutz: Bewerbungsdossier darf nur mit Zustimmung des Kandidaten weitergeleitet werden

Vermittler, welche sich nicht an den Datenschutz halten und Personaldossiers ohne Zustimmung des Kandidaten weiterleiten, machen sich strafbar.

Sollten sich Vermittlungsagenturen nicht an diese Regeln halten, drohen der Entzug der Bewilligung, sowie eine hohe Busse. Zusätzlich verlieren diese Vermittler ihre Reputation (wenn sie jemals eine hatten). Aber eben – in der Not werden auch solche Mittel angewandt.

Source: SplitShire.com

Gesetzliche Hürden zu tief

Personalvermittler kann jeder werden und es lockt das schnelle Geld. Zum einen gibt es keinen geschützten Titel als Personalvermittler und zusätzlich sind die gesetzlichen Hürden, um selbständiger Personalvermittler zu werden relativ tief. Eine Einzelunternehmung ist schnell gegründet und nach der Beantragung einer Bewilligung für die Vermittlung, welche zwischen 750 und 1‘650 Franken kostet, stehen die Türen zur Vermittlung von Personal offen.

Bei dem Personalverleih ist die Hürde mittels einer Kaution in Höhe von mindestens 50‘000 Franken höher. Zusätzlich gibt es im Personalverleih mehr Pflichten auf Seiten der Agentur, da diese der gesetzliche Arbeitgeber des Vermittelten ist.

Personalvermittler werben ab

Pascal schreibt in seinem Blogeintrag, dass Personalvermittler probieren seine Mitarbeiter abzuwerben. Über die Social Networks ist es sehr einfach geworden nach Personen mit bestimmten Fähigkeiten und Kenntnissen zu suchen und mit diesen in Kontakt zu treten. Personalvermittler bauen ein Netzwerk aus Kandidaten, Kunden, HR-Verantwortlichen etc. auf. Aus einem ehemaligem Kunden (Linienvorgesetzten) kann schnell ein potentieller Kandidat werden und umgekehrt.

Es ist aber nicht die Schuld der Personalvermittler, dass die eigenen Mitarbeiter zu anderen Unternehmen wechseln. Hier ist es eher die Aufgabe des Unternehmens ein möglichst attraktives Umfeld für seine Mitarbeiter zu schaffen. Dies kann durch Wertschätzung, Freiraum, Personalentwicklung (Weiterbildung, Trainings der Mitarbeiter) und natürlich auch durch finanzielle Anreize sein. Zufriedene und loyale Mitarbeiter lassen sich nicht abwerben. Und sollte sich ein Mitarbeiter doch abwerben lassen, war dieser vielleicht nicht mehr zufrieden und dadurch weniger engagiert und produktiv.

Kosten eines Vermittlers

Pascal schreibt, dass er sich persönlich um neue Anstellungen kümmert. Dies ist lobenswert und wichtig um Mitarbeiter zu finden, die zum Unternehmen passen und wer kann das besser beurteilen als ein Mitgründer von Simplificator?

Aus Unternehmenssicht ist eine Zusammenarbeit mit einem Personalvermittler auf den ersten Blick mit hohen Kosten verbunden. Nicht zu vernachlässigen sind aber die Kosten für die Ausschreibung einer Stelle, der zeitliche Aufwand den Rücklauf der Bewerbungen zu prüfen, Fragen von Bewerbern zu beantworten, Bewerber absagen, Interviews zu vereinbaren und so weiter. Ich bin der Ansicht, dass spezialisierte Partner einem Unternehmen helfen sich auf die eigenen (wertschöpfenden) Kernkompetenzen zu konzentrieren. Mit einem professionellen Personaldienstleister ist es auch möglich Lösungen zu finden, welche von der klassischen Vermittlung abweichen.

Mögliche Wege wären Try-and-Hire, einen neuen Mitarbeiter zuerst via Personalverleih befristet anzustellen (wobei alle Arbeitgeberrisiken beim Verleiher bleiben) und danach die Option einer Festanstellung zu haben oder mittels Mandat, bei dem das Unternehmen und der Personalvermittler einen Fixpreis für eine bestimmte Anzahl Stellen vereinbaren. Da der Personalvermittler hier exklusiv für den Kunden arbeitet und es eventuell eine Option auf zusätzliche Anstellungen gibt, ist der Preis tiefer als bei einer klassischen Vermittlung. In Pascals speziellem Fall empfehle ich bestimmte Rekrutierungsprozesse an einen Personaldienstleister abzugeben (Recruitment Process Outsourcing). So könnten zum Beispiel die Stellenausschreibung, die Verarbeitung der Bewerbungsunterlagen und die Organisation der Interviews an einen Partner abgegeben werden.

Fazit

Unzählige Anrufe von Vermittlern zu bekommen oder ungefragt einen CV zu erhalten, bietet keinen Mehrwert für den Kunden. Ein guter Dienstleister bietet dem Kunden Lösungen an, welche ihm helfen seine tägliche Arbeit einfacher und besser zu machen, dies muss auch bei Personalvermittlern so sein.

Vielleicht können meine Ausführungen Pascal davon überzeugen, nicht die gesamte Branche der Vermittler vorzuverurteilen und einem Personaldienstleister irgendwann eine Chance zu geben.


Christoph Dopp ist bei Harvey Nash zuständig für das Contract Management Team in Zürich. Momentan betreut sein Team mehrere hundert Spezialisten, welche bei diversen Kunden in der Schweiz im Einsatz sind. Unter den Kunden befinden sich Unternehmen der IT-, Pharma-, Industrie- und Finanzbranche.

Seit 1988 rekrutiert Harvey Nash die besten Experten für Festanstellungen und Projekte für eine Vielzahl von führenden Unternehmen in der Schweiz und im Ausland. Harvey Nash operiert von 43 Standorten in Nordamerika, Asien, Australien und Europa aus und beschäftigt weltweit über 8‘000 Mitarbeiter und Experten. In der Schweiz ist Harvey Nash mit Niederlassungen in Zürich und Genf vertreten.

Christoph auf LinkedIn und Xing

Rails Girls Helsinki

Two Simplificators, Marion and Ferdinand, have been to Rails Girls in Helsinki as coaches. Here is a short travel report.

Friday

We arrived in Helsinki on Friday and went to meet the Rails Girls organizers of smartly.io in their office, where they welcomed us graciously. They could not believe that we flew to Helsinki just for the event and called us crazy people :). When they had the installation party, Ferdi and I went to explore the city. We met them again for dinner, where we had so much fun getting to know all the organizers and coaches.

Ferdinand coaching

Saturday

The event was a cooperation between smartly.io and vamos!, which is a charity organisation that looks after young people who have social difficulties and don’t know what to do with their lives. For this reason, there were some boys attending the event as well. There were also two boys who wanted to become DJs, and so this was a perfect event for them to practice.

Marion presenting

The day started with a lengthy breakfast at the smartly office before the event, which is always nice. Then, I had a small talk about how I came to be a little programmer and why we flew all the way from Zurich. After this introduction, the workshop started. Ferdi and I coached a group of three girls together: two girls from Finland and one from Taiwan. We went through the Rails Girls tutorial, creating a simple website. It was strange to once know more about programming than others for a change, and I think I succeeded in answering their questions in a woman-friendly way. When I couldn’t answer a question, Ferdi was right there to explain. They were already done with the tutorial by lunchtime, so we advised them to actually learn a little more Ruby with Code School. It was really amazing how motivated the girls were, and that they didn’t give up when things didn’t work out right away. Also, they were eager to find out how these programming languages work, and really kind of got the hang of Ruby by the end of the day.

All in all, it was a great weekend and I have learned a lot. And more importantly, I am so happy to have been able to help these girls understand Ruby on Rails. Maybe, one of them will find her way into programming after the event.

Personalvermittler

iPhone no caller ID

Wir 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 mir 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?

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 1x1, 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.