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!

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.

Filter Rails SQL log in production

In order to debug a problem, which only occurred in production, we recently wanted to tweak our Rails SQL logs to only show the access to a specific table.

Here’s what we did to accomplish this. We created a file initializers/filter_sql_log.rb with this content:

if Rails.env.production?

  module ActiveRecord
    class LogSubscriber
      alias :old_sql :sql

      def sql(event)
        if event.payload[:sql].include? 'users'
          old_sql(event)
        end
      end
    end
  end

end

This monkey-patches the ActiveRecord::LogSubscriber class and only delegates to the old logging method, if the SQL statement includes the string "users".

By default, SQL logging is deactivated in the Rails production environment. Therefore we needed to change config/environments/production.rb like this:

config.log_level = :debug

Configuration load order in Rails

Ever wondered what the load order of the various configuration files of Rails is?

In Rails the (more or less) common places to configure your app are:

  • application.rb
  • config/environments/*.rb
  • config/initializers/*.rb
  • after_initialize callbacks (in application.rb or in environment specific files)

Since there is multiple points where you can add the configuration the order in which those configurations are applied is important. E.g. it might happen that you set a value in one place and it gets reverted from another config file. This is the order that get’s applied, tested in Rails 4.2

  1. application.rb
  2. environment specific config file in config/environments/*.rb
  3. initializers, they are loaded in alphabetical order
  4. after_initialize callbacks, in the order they have been added

Wie können wir überhaupt in der Schweiz entwickeln?

Ist es nicht viel zu teuer in der Schweiz Software zu entwickeln? Sätze in Indonesien, Indien, China oder Polen sind Faktoren tiefer als in der Schweiz. Warum müssen wir denn hier entwickeln? Mit Skype und allem müsste es doch einfach sein, im Ausland zu entwickeln – so kostengünstig dass eventuelle Kostenabweichungen oder Ineffizienzen überwunden werden können. Irgendwas stimmt mit dieser Rechnung offenbar nicht.

image

(Infosys, Bangalore. Picture from Wikimedia)

Es gibt es mehr und mehr Entwicklungen die wieder in der Schweiz gemacht werden. Die Industrie ist gesund, alle Software-Bauer suchen Entwickler, in den verschiedensten Technologien. Offenbar ist es doch nicht so einfach im Ausland zu entwickeln: Wir kennen viele Projekte, die fehlschlugen oder nahezu fehlschlugen, frustrierte Kunden, Entwickler die schlechten Code pflegen und wütend unter Zeitdruck Bugs von anderen fixen müssen, und mit etwas Wohlwollen finden wir vielleicht eine einzelne Referenz von einem gelingenden Projekt. Warum diese Diskrepanz? Es müsste doch gehen, es müsste doch günstiger sein, seid ihr Softwareentwickler denn alle nicht interessiert daran?

Das Problem daran ist, dass solche strategischen Entscheide nicht von denselben Personen gefällt werden, welche die technischen Entscheide fällen. Die Recheneinheit ist die Mannstunde oder der Manntag. Klar ist jedem bewusst dass eine Mannstunde in Indien nicht dasselbe heissen muss wie in der Schweiz. Aber die Mannstunde hält immer noch hin als “Proxy” für reale Entwicklungsleistung. Und das ist der Kern des Problems: Was wenn ich behaupte, der Overhead von Missverständnissen, Bürokratie, falsch verstandenen Aufgaben und blanker Unfähigkeit beim Auftragnehmer kombiniert einen Faktor fünf bis zehn ausmacht? Wie sieht es dann aus mit dem Kostenvorteil?

Pascal Betz und ich haben 2006 zusammen vor der Gründung von Simplificator einige Projekte in Bangalore, Indien durchgeführt, für unseren Schweizer Arbeitgeber. Wir haben dabei gelernt, was die Probleme sind: Kommunikation, Organisation, fehlender gemeinsamer Kontext. Diese Aspekte sind wichtiger, als wir uns vorgestellt haben. Software zu bauen ist nicht nur eine technische Herausforderung, sondern eben vor allem eine menschliche. Wir bauen nicht einen einzelnen Prozess auf, den wir dann wiederholen können (wie zum Beispiel bei industrieller Produktion von iPhones). Wir betreiben nicht nur Bau, sondern auch Forschung, Entdeckung, Planung. Und das sind genau die Dinge die in der Übersetzung verlorengehen – sozusagen “Lost in Translation”. Die Komplexität die in Softwareentwicklung inhärent ist trägt dazu bei, dass die wahren Probleme nicht wahrgenommen werden: Es ist so einfach zu sagen dass der Auftrag nicht klar genug formuliert worden ist, oder dass Softwareentwicklung halt mit Risiken verbunden ist.

“Und sowieso habt ihr ja den Vertrag so unterzeichnet und dort steht das ja genau so wie wir ihn erfüllt haben – wie kann es denn unser Fehler sein wenn ihr uns nicht sagt was ihr braucht.”

Genau. Danach können nur noch Anwälte Geld verdienen. Zurück zur Schweiz:

image

Wie wäre es, wenn Softwareentwicklung wieder als Arbeit verstanden werden könnte, nicht als Magie, zu erledigen von abstrakten Ressourcen, die ihre Manntage in Cubicles irgendwo auf der Welt als erledigen, sondern Menschen mit denen man reden kann? Die regelmässig mit Papier und Bleistift Annahmen klären, Dinge visualisieren, den Auftraggeber zurück in die kontrollierende Position rücken? Die die Fragen fragen die sie interessieren, expliziter von implizitem Bedarf unterscheiden? Statt Jaja-Sklaven echte Diskussionspartner, die teure Fehlentscheidungen rechtzeitig hinterfragen, Rückfragen, keine Angst haben die grossen Entscheidungen anzuzweifeln?

image

Der Ausbildungsstandard in der Schweiz ist hoch. Wir haben ein Qualitätsverständnis, und eine Ehrlichkeit. Wir haben weniger Hierarchiegläubigkeit als andere. Das macht es vielleicht am Anfang des Projektes anstrengender, aber dafür kommt etwas dabei raus. Als wir das herausgefunden haben, haben wir verstanden dass wir in der Schweiz eine Chance haben mit einer eigenen Firma.

  1. Die Kosten pro Stunde sind höher. Aber die Effizienz eben auch.
  2. Wir sehen dass Komplexität nicht weg-abstrahiert werden kann, sondern gemanagt werden muss. Also steht und fällt der Erfolg mit der Fähigkeit, mit Komplexität umgehen zu können.
  3. Persönliche Treffen haben die höchste Bandbreite von zwischenmenschlicher Kommunikation.
  4. Papier und Bleistift sind immer noch durch nichts zu ersetzen.
  5. Agile, iterative Entwicklung verlangt nach dauernder Kommunikation und Anpassung der Ziele.
  6. Der Umgang mit Komplexität verlangt nach agiler, interaktiver Entwicklung.
  7. Wenn es einfach wäre, hätten wir keinen Job. Der Umgang mit der Komplexität ist der Kern unserer Arbeit.

Deswegen heisst die Firma Simplificator GmbH.

Damit bekommen wir einen finanziell wertvollen Standortvorteil in der Schweiz, verstärkt durch Anwendung von agilen Technologien und Vorgehensweisen. Darum müsste es klappen.

Und es hat geklappt.

Was heisst das nun?

Es heisst, dass es finanziell schlau sein kann, in der Schweiz zu entwickeln, und dass das nicht ein bequemer Luxus ist, sondern ganz konkret mit dem Schaffen von realen Werten zu tun hat. Software die vor Ort mit guten Partnern entwickelt wird, ist summa günstiger. Das mag wegen oben genannten Gründen nicht von Anfang an sichtbar sein. Aber unsere Erfahrung und diese Überlegungen schaffen nicht nur ein emotionales, sondern auch ein rationales Argument für die Entwicklung von Software in der Schweiz.

Und jetzt kommt der sogenannte “Call to action”: Wir können auch einfach mal drüber sprechen, es muss nicht gleich ein Projekt daraus entstehen. Wir beraten auch, machen Qualitätssicherung, oder Hosting in der Schweiz. Und wir haben guten Kaffee. Ruf an.

Jetzt. :-)

Kontakt: 044 500 47 50, info@simplificator.com oder @simplificator. Wir freuen uns.

Webtuesday about Rails

Our customer local.ch is hosting a Webtuesday tonight at 19:30, where Jeremy talks about the experience of introducing Ruby on Rails, an effort Simplificator was able to support in several projects. Location: the local.ch office at Konradstrasse 12, 8005 Zürich. More info here – the gist of it below.

War stories from 1 year of running local.ch on Rails

local.ch went live with Rails in March 2012. As with any new technology stack, handling high traffic, not everything went smoothly. Jeremy Seitz shares stories, experiences and lessons learned on bringing one of the most popular websites in Switzerland to Rails.

Speaker

Jeremy works at local.ch as lead engineer on the website. He has many years experience of Rails and software development more about which can be discovered at his website

Sign up

Please sign up at techup.ch