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.

Clean your backlog

· Dimiter Petrov

Have you recently checked the size of your backlog?

There is a limit to the amount of work a team can do at a given time, so new tasks get queued in a backlog. As a project grows, so does its backlog. There are new features to develop, more bugs to fix, but these tasks take longer to finish than to write down.

The problem with large backlogs

Large backlogs are demoralizing. It is intimidating to realize how much is left to do.

Large backlogs are overwhelming. People lose the overview. They create a second, smaller, "prioritized" backlog. Or they start tracking work through other channels: in-person meetings, email, text chat. That exacerbates the problem - now you have multiple backlogs and they all keep growing.

Large backlogs stagnate. The bigger the backlog, the more information is outdated and the more maintenance is required.

Large backlogs give a false sense of how much is really planned, because most items are too vague or not estimated yet.

Keep your backlog small(er)

Reducing the backlog size can reduce the team's stress level. It also allows the team to focus on what's the most important. Here are some ideas to help you declutter:

Tips for applying to a job at a small company

· Dimiter Petrov

As a small software company, we at Simplificator handle the entire hiring process on our own. We find that gives us the best results. I've been helping review job applications and interview candidates for more than 4 years. Here are some things I've observed that influence the success of an application.

Motivation letter

I look for two things in a motivation letter:

  1. interest for the job position or company;
  2. how the person's experience relates to the job offer.

Interest for the company

A single person has a big impact in a small company. That's why it's important that everyone finds their work meaningful and motivating. It's hard to tell if that's the case before the trial period, but you get a hint if you work through a representative problem together during technical interviews. If I have to choose who to interview, I'd rather pick candidates who've given enough thought about whether they'd like this particular job.

Show you've done research:

The last one is not about flattery. Even if you don't find anything "exciting" about the company, surely there's something you could get out of working there, besides money. Do you want to learn a specific skill? Do you want to gain experience in a company of a certain size? Do you want to change your work mode to improve your work-life balance? Answering such questions doesn't just help a company decide whether they want to work with you. It also helps you refine your job search.

Demonstrating how your experience fulfills the requirements

Don't just say "I fit the job description perfectly". Give concrete examples of how you meet the criteria in the job listing.

It's tempting to just rephrase the contents of the CV. Instead, try highlighting which skills or specific parts of past jobs relate to this offer.

Counter-intuitively, stating in which ways you don't fit the job description and how you plan to address that can play in your favour as well. Job offers often make it sound like companies are looking for a candidate who fits a certain mold. However, the right hire can also transform their job for the benefit of the entire team. If you're unsure about the strictness of the requirements, get in touch with the company to clarify. A phone call can give you a new perspective.

CV

Include experience from areas of work other than the core role for which you are applying. Your expertise will be valuable in a small company which cannot have a specialist in every field. As an example, here are some skills from seemingly unrelated domains that remain relevant at a software agency:

General CV advice - like keeping it short and structuring it around impact - still applies.

Work sample

Companies may ask to send them a product of your work, especially for technical positions. Sometimes that is a take-home assignment, sometimes it's an extract from prior work.

Take-homes are time-consuming when applying for multiple positions, so we prefer a sample from existing work. We also request something similar for non-technical positions (see below).

Code sample

If you need to provide a code sample, make it easy to find and read. The reviewer won't know what to look for if you've linked your entire GitHub profile.

Point to a specific piece of code you're proud of or find interesting. That could be a class or module. It could be a single commit that fixes a bug with a commit message explaining when and why the bug occurs, why your fix works and what alternatives there are.

"I can't share code written for my current employer"

You don't have to. It's also okay if you don't have a side-project and don't code outside of work. However, if applying at multiple companies, consider creating something small that you can present to all of them.

You could:

Other types of work samples

Your line of work does not involve coding? You can still describe how you work. Maybe you can share a blog post about how you solved a problem at work, or a presentation you've given about an achievement. Feel free to link to them in your cover letter or CV.

Further resources

A subtle change in PDF output

· Dimiter Petrov

The problem

I had dockerized a Rails application, but a test was failing when run within the Docker container. The relevant code is:

pdf_string = PdfGenerator.new(input).generate
pdf_pages = parse_pdf(pdf_string)

expect(pdf_pages[2]).to include(
'A rather long line from the PDF that was in the original test, ' \
'but which I have substituted for the purposes of this example'
)

It renders a PDF, then parses it with pdf-reader and asserts that some text is on page 3 of the document.

The expectation failed, but the diff showed that the text was on the page. However it was on two lines instead of one.

Sure, one could put a line break in the test and call it a day:

expect(pdf_pages[2]).to include(
"A rather long line from the PDF that was in the original test, " \
"but which I have substituted for the purposes of this\nexample" # Note the \n
)

I didn't give up so easily.

The motivation

As an agency, we have our set of practices and documentation about running software. That makes provisioning, monitoring, backups, knowledge sharing, etc. easier. The application in question was an exception. It had been built by someone else and had been in production for years before Simplificator took over development and maintenance. We wanted to move it to our infrastructure eventually, but we had decided to get familiar with the code first.

After a few months of developing new features and fixing bugs, we knew enough to migrate to a new server with more confidence. Running the application in Docker was one step of the process and this is when I ran into the test failure above.

I did not cheat and change the test, because even though it looked like an insignificant detail, it could be something more. Whenever you make an infrastructure change you find things that were assumed, but undocumented, things that were done once manually and forgotten. We had written the PDF generation test in the phase when we were getting to know the codebase. Now this test was helping us consistently observe a difference in behaviour between two environments (Docker and no Docker). A rare chance!

The search

The application generates PDF files using wkthmltopdf. That is, Rails renders an HTML template, then wkhtmltopdf converts the HTML document into a PDF. The problem could be in any of these, so I tried to narrow it down.

First, I checked the page dimensions. A narrower page would have shorter lines. That was not it. wkhtmltopdf saves A4-formatted pages by default. The page margins were also expressed as absolute numbers.

Then I tried to open the PDF generated withing Docker with the PDF viewer on my host. I wanted to get the PDF from the test. The test has everything set up to render the exact document that reproduces the bug. In the application I would have to fill out some forms, which takes much longer. I ran into some permissions problems getting the file out of the container. I went down that rabbit hole for longer than expected (as one does).

Frustrated, I tried at least generating the PDF from outside a container and copying it into the container for comparison. I ran the test outside Docker, opened the PDF and knew immediately what the problem was.

The realization

The font in the PDF I had just built looked slightly different from the font I'd seen in documents generated in production.

I found the CSS rule:

font-family: Helvetica, Arial, sans-serif;

The developer who wrote the test was using macOS, so the Helvetica font was present.

The production Linux server had neither Helvetica nor Arial. It did have a different replacement font that was apparently close enough in dimensions:

$ fc-match Helvetica
DejaVuSans.ttf: "DejaVu Sans" "Book"

The tests had so far been running on the default image provided by the continuous integration service. That image is based on Ubuntu and has many packages pre-installed, so it probably also had a close-enough fallback.

The new Docker image, though, only had the bare minimum needed to run the application. It didn't even have Deja Vu Sans. So it must have been using a different sans serif font, which has wider shapes, making less text fit on a line.

Sure enough, including Nimbus Sans in the Docker image as a fallback for Helvetica fixed the test.

Zur Junior Softwareentwicklerin in 5 Schritten

· Tatiana Panferova

Hin und wieder werde ich gefragt, was man beachten muss, wenn man sich Mitte 30 nochmals beruflich neu orientiert. Ganz einfach: Mut fassen und Prioritäten setzen. Klar ist das nicht so einfach, wie es klingt. Klärt man für sich jedoch einige wesentlichen Punkte, wird aus dieser komplexen Entscheidung ein gangbarer Weg sichtbar. Meiner sah so aus:

Schritt 1: Wissen, was man nicht will. Bevor ich mich für den Karriereschritt zur Softwareentwicklerin entschied, habe ich lange im Journalismus gearbeitet und war danach als Fotografin selbstständig. Letzteres erforderte eine grosse Flexibilität in Bezug auf Arbeitszeit (z.B. Wochenendaufträge), was mit meinem Privatleben langfristig nicht vereinbar war. Auch wusste ich, dass das Thema Kundenakquisition mir persönlich sehr viel abverlangte. Ganz gleich in welcher Branche - eine künftige Tätigkeit sollte diese beiden Aspekte nicht beinhalten.

Schritt 2: Wissen, was man will. Da ich zu dem Zeitpunkt bereits eine Familie hatte war klar, dass ein mehrjähriges Studium nicht infrage kam. Ich suchte also nach einem schnellen Einstieg in eine neue Branche. Mir war wichtig, einen “echten Skill” zu beherrschen. Das neue “Handwerk” sollte mir zudem karrieretechnisch Sicherheit verschaffen. Last but not least war mir das Arbeitsumfeld sehr wichtig: gute Kolleg*innen, ein Büro, in dem man sich trifft, Arbeitsprozesse, die unkompliziert ablaufen. Auf dieser Grundlage wurde mir sehr schnell klar, dass eine Ausbildung im Tech-Bereich für mich infrage kam.

Ich hatte bereits Erfahrung in der IT-Branche gesammelt, während ich als Intranetportal Editor in einer grossen IT Firma in Moskau arbeitete. In dieser Funktion habe ich Artikel über unsere Software-Produkte geschrieben und mein Interesse daran, wie Software tatsächlich gebaut wird, wurde immer grösser. Zudem habe ich die Atmosphäre und die Menschen sehr geschätzt. Ich habe festgestellt, dass meine Kolleg*innen ähnlich denken wie ich und so auch gemerkt, dass ich gerne wieder in der IT arbeiten möchte, aber diesmal mehr als Techie.

Schritt 3: Informationen und Touchpoints. Ich war nicht sicher, ob ich mit meinem Background Entwicklerin werden könnte und dachte erst mehr an eine Position wie z.B. Product Manager. Aber bei der Recherche habe ich festgestellt, dass ich dennoch eine technische Grundausbildung benötige, und, was noch viel wichtiger ist, Erfahrung in der Entwicklung. Also habe ich mich entschieden, ganz von vorne zu beginnen und Webentwicklung zu lernen.

Dazu las ich viele Blogposts von anderen Frauen, die den Quereinstieg geschafft hatten und fühlte mich dadurch ermutigt.

Schritt 4: Ausbildung. So habe ich angefangen, mich über praxisnahe Ausbildungsmöglichkeiten schlau zu machen und ich rate allen, sich damit zu befassen, welche Angebote online oder auf deinem lokalen Markt existieren und dich mit Studierenden oder Alumni der Schule auszutauschen. Gerade im IT-Bereich existiert eine Vielzahl an Anbietern, die mit Crashkursen zum Einstieg in die IT-Karriere werben. Persönlich war für mich klar, dass ich die Ausbildung Vollzeit absolvieren wollte, sie jedoch nur einige Monate dauern sollte. So habe ich mich für einen dreimonatigen Full-Stack Programmierkurs bei Propulsion Academy angemeldet. Die Lernerfahrung war intensiv, jedoch sehr bereichernd.

Schritt 5: Vernetzen, Vernetzen, Vernetzen. Nun hatte ich 3 Monate Programmieren im Rucksack und war voller Hoffnung, eine Anstellung als Junior Softwareentwicklerin zu finden. Entwicklerinnen sind auf dem Arbeitsmarkt bekanntlich sehr begehrt. Schnell musste ich jedoch feststellen, dass dies nicht zwingend für Junior Positionen oder gar Praktika gilt. Auf viele meiner Bewerbungen habe ich keine Rückmeldung erhalten. So schlug ich einen anderen Weg ein. Anstatt mich auf Ausschreibungen zu bewerben, ging ich proaktiv auf interessante Personen oder Unternehmen zu und nahm an Hackathons und Meetups teil. So wurde ich auch auf Simplificator aufmerksam - und sie auf mich. Simplificator führt in ihrem Büro ein wöchentliches Coding-Meetup zu Ruby on Rails durch. Nachdem ich an einem weiteren Meetup bei Simplificator zum Thema Testing teilnahm und mir die Atmosphäre dort sehr gut gefiel, nahm ich meinen Mut zusammen und fragte, ob sie ein Praktikum anbieten. Kurz darauf traf ich mich mit unserem CEO Lukas und durfte dann als Praktikantin starten. Nun bin ich einer Festanstellung als Junior Softwareentwicklerin tätig und mache das, was ich am Anfang meines Karrierewechsels wollte.

Ich wünsche allen, die mit einem Einstieg in die Tech-Branche liebäugeln viel Erfolg, Mut und Ausdauer. Dranbleiben lohnt sich.

Inhalt: Tatiana Panferova
Text und Übersetzung: Patricia Leventis, Miriam Schütz

Ein Tag mit Simplificator im Homeoffice

· Claudia Züchner, Raphael Müller

So organisieren wir uns in dieser aussergewöhnlichen Zeit

Es ist eine Zeit mit vielen Herausforderungen, sowohl geschäftlich als auch im privaten Umfeld. Man startet in den Tag mit einem Update zu den Zahlen rund um das Coronavirus und wird täglich mit einem Anstieg der Erkrankten und Todesfälle konfrontiert. In der Schweiz sind inzwischen 56 Personen am Coronavirus gestorben, 6113 sind infiziert. (Stand 22.03.2020, 10:30 Uhr) Der Bundesrat hat die «ausserordentliche Lage» ausgerufen.

Um das Wachstum dieser Zahlen zu verlangsamen, hat der Bundesrat verschiedene Massnahmen ergriffen - unter anderem das Einschränken des öffentlichen Lebens. Doch physische Distanz heisst nicht gleichzeitig soziale Distanz. Gerade in Zeiten wie diesen ist Kommunikation extrem wichtig. Gemäss einem unserem Grundsätze “dare to question” steht bei uns auch in der aktuellen Situation Kommunikation an oberster Stelle. Wir entwickeln nicht einfach drauf los, sondern wir finden zuerst heraus, was unsere Kunden benötigen. Dazu gehört auch, dass man als Team eng zusammenarbeitet und sich permanent austauscht.

Doch wie erreichen wir das trotz Homeoffice bzw. den Einschränkungen durch das Coronavirus?

Unseren gemeinsamen Tag beginnen wir jeden Morgen mit einem virtuellen Standup Meeting via Zoom. Das Ziel ist ein kurzer Austausch über die Aufgaben jedes Mitarbeiters und jeder Mitarbeiterin und ob man auf Projekten zusammenarbeiten kann, um sich gegenseitig zu unterstützen. In diesem Zusammenhang haben wir auch einen Blick auf Moco, unser Planungs- und Zeiterfassungstool. Die Planungsübersicht zeigt uns übersichtlich welcher Mitarbeiter in den kommenden Tagen auf welchem Projekt arbeitet.

Standup Meeting via Zoom

Da auch ein Arbeitstag im Homeoffice nicht um 12 Uhr vorbei ist, treffen wir uns im Team noch einmal am frühen Nachmittag zu einem virtuellen Coffee-Break. Diese tägliche Kaffeepause gibt Raum für Themen, die nicht zwingend mit der Arbeit zu tun haben und fördern das soziale Miteinander in dieser aussergewöhnlichen Situation.

Regelmässige Videocalls über den Tag verteilt helfen uns, uns in kleineren Teams abzusprechen, Fragen zu stellen und uns auszutauschen sowie etwas zu diskutieren. Auch mit Kunden und Leads stimmen wir uns aktuell über diesen Kanal ab.

All unsere Systeme sind von zu Hause erreichbar und wir sind uns bereits gewohnt ab und an remote zu arbeiten. Slack erweist sich dabei für uns als unerlässliches Tool zur textbasierten Kommunikation untereinander als auch mit unseren Kunden. Unser Grundsatz “Collaborate closely” nimmt noch mehr an Bedeutung zu, damit wir in dieser Zeit die Bedürfnisse unserer Kunden erkennen und auch lösen können. Wir stehen in direktem, regelmässigen Kontakt mit jedem Einzelnen und versuchen dort zu helfen, wo es uns braucht.

Doch neben all den technischen Möglichkeiten, die uns die Zusammenarbeit erleichtern ist es wichtig, dass man sich zu Hause ein geeignetes Umfeld zum Arbeiten schafft. Ein separater Arbeitsplatz an dem man sich besser auf die Arbeit konzentrieren kann, ist enorm hilfreich. Darüber hinaus hilft ein strukturierter Tagesablauf mit fixen Pausen z.B. für Sport.

Allerdings sehen wir auch, dass Homeoffice nicht für alle Branchen umsetzbar ist. Was macht der Blumenladen um die Ecke, dessen Lager mit frischen Blumen voll ist? Was macht das Geschäft mit Kinderkleidern, welches die aktuelle Frühjahrskollektion bestellt, aber nun stationär nicht verkaufen darf? Ein Webshop kann hier vielleicht Abhilfe schaffen, so dass auch diese Unternehmen weiterhin für ihre Kunden da sein können. Wir sind dabei, uns einfache Lösungen zu überlegen.

Für Unternehmen, die von zuhause aus arbeiten können und ihre eigenen Server im Büro haben, lohnt es sich, ein VPN einzurichten und sicherzustellen, dass jeder Mitarbeiter auf einfache Art auch remote Zugriff hat.

Wir sehen, dass besonders in Zeiten des Coronavirus eine enge Zusammenarbeit und der Austausch untereinander wichtig sind. Natürlich wären direkte Kontakte vor Ort in vielen Fällen besser - die digitalen Varianten sind aber gute Alternativen.

Gerne beraten und unterstützen wir, sollte jemand Hilfe benötigen in Bezug auf Remote Collaboration - technischer oder auch organisatorischer Art.

Physical distancing doesn't mean social distancing - rather collaborate closely.

A new, simplified blog

· Lukas Eppler

There is one obvious way that makes it easier for coders to write blog posts.

We tried everything before: First we wrote our own thing. Of course. It was a simple database and we wrote our own markup parser - well, it was 12 years ago and there wasn't much around rails yet. And for the first year or so, it was just a blog. After some time Radiant CMS came out and we gave it a spin. It worked, it was quite ok. We struggled greatly with the multilingual part, but had something running. Unfortunately I don't have screenshots of the blog - and the wayback machine has no recollection of our CSS, so I won't post screenshots here. It wasn't grand either, but already fairly political (I ranted about the SUISA fees, which is now the reason why it is now apparently legal to use torrent software in Switzerland). I found a screenshot of the front page:

Simplificator Front Page in 2010

But it was also very technical, we were proud of working with Ruby on Rails, almost as much as we're proud now of working with Elixir and Phoenix.

We then had the idea to link the different aspects of our work together: We write projects, using technologies, with customers. Page visitors should be able to see what we do, who we are, and the connecting link was technology. Several developers will develop a project, one project was always for one customer, one customer might have many projects. There will be several technologies used (Ruby on Rails, Javascript in most cases, but also jQuery, Cucumber, RSpec, Heroku and many more). So we linked them together. To make sure the links stay consistent we rolled our own thing again.

Simple is not easy. So our page grew, and it became apparent that we're inflexible. It got out of date. It was slow. It wasn't ideal for all this new fancy SEO strategies. We expanded and tweaked. And our own system survived. But we found out that we're so far behind that it's hard to catch up. Was it worth it?

Simplificator Front Page in 2019

We did a redesign, mostly to support mobile, and streamlined everything optically. But then we stopped: Our leads come from connections and people who experienced working with us, rarely through google. We needed to not suck on our page, so we don't deter anyone, but even if we would triple our leads from the web site it would contribute close to nothing to our bottom line. So we focused on other topics. To ease some pain with the blog, we moved it to WordPress. A complete admission of defeat.

Last summer, things started to move again. We changed the way we organize ourselves and how we take decisions (more about that later). So some of us took initiative and started rewriting, taking the best technologies available to create a top-of-the-line solution, with deployment pipelines, static rendering, CDN and the best of all, our blog content is now on GitHub. We can write however we like with the editor of our choice, issue pull requests for feedback, and publish with a commit. And suddenly, we (or at least I) write blog posts again.

The issue why we procrastinate about stuff like writing blog posts is not the technology. Our habits and what we love to do define what comes easy. Procrastination is often a sign that we strayed away from what we're good at. We're not procrastinating about what we love to do. If that is writing code, committing and writing pull requests, let us hook into that.

So now, to write this blog post, I added a file to our repository (which is public on GitHub, by the way), and issued a pull request. I have asked others to pitch in, and after I took in all the feedback I got, this post will be merged and published.

This is a way to make it easy for coders to publish blog posts.

To have a process like that is not easy to set up. But when it's done it is as it should be: simple.

Setting up Cypress with Rails

· Dimiter Petrov

Cypress.io has very nice tooling for testing. We have been experimenting with it in various projects, one of which is a Rails application.

Cypress is not the obvious choice for Rails, since Rails comes with system tests out of the box since version 5.1. Before that Capybara was also not hard to set up.

Over the years we've gone back and forth on Selenium-based tests mainly due to how easily they can become slow and flaky. We're now trying to see if Cypress can help in this aspect.

There are a few subtleties about integrating Rails with Cypress.

First of all, if your frontend communicates with the backend through an API, Cypress makes it easy to test the frontend in complete isolation. In this application however we are dealing with a classic server-rendered user interface that achieves some of the interactivity with "sprinkles" of JavaScript. That means that we have to run the Rails server in order to test the UI.

I first looked at the cypress-on-rails gem, but it permits running arbitrary code (!) and generally seems to do too much. Manual setup it is then.

Running Rails during Cypress tests

Cypress knows nothing about the backend and expects it to be running already. We can get there with a helper script:

#!/usr/bin/env bash

RAILS_ENV=test bundle exec rake db:environment:set db:create db:schema:load
bundle exec rails server -e test -p 5002

Then we tell Cypress how to find it using the baseUrl setting in cypress.json:

{ "baseUrl": "http://localhost:5002" }

Cleaning up between tests

Because the test backend is a long-running process and the tests can (indirectly) modify the database, we need to make sure every test starts with a clean slate.

One way to do it is to expose an API that is only available during tests.

# config/routes.rb

Rails.application.routes.draw do
# ...
if Rails.env.test?
require 'test_routes'
define_test_routes
end
end

The necessary routes are defined in a separate file on purpose. First, the file name itself warns that they are for the test environment. Second, the conditional inclusion in the router is easy to scan and there's no chance to accidentally define test routes outside this conditional, no matter how many there are.

Let's define a route for the database cleanup:

# lib/test_routes.rb

def define_test_routes
Rails.logger.info 'Loading routes meant only for testing purposes'

namespace :cypress do
delete 'cleanup', to: 'cleanup#destroy'
end
end

The controller contains this:

# app/controllers/cypress/cleanup_controller.rb

class Cypress::CleanupController < ActionController::Base
def destroy
if !Rails.env.test?
return head(:bad_request)
end

tables = ActiveRecord::Base.connection.tables
tables.delete 'schema_migrations'
tables.each do |t|
ActiveRecord::Base.connection.execute("TRUNCATE #{t} CASCADE")
end

head :ok
end
end

The guard clause is there to be extra careful, because we then truncate all application-defined tables! We keep the migrations information intact and remove the data from all other tables. No need for a gem like database_cleaner.

Now that the API endpoint is there we can wrap it in a custom Cypress command.

// cypress/support/commands.js

Cypress.Commands.add("resetDatabase", () => {
cy.request('DELETE', '/cypress/cleanup').as('cleanup')
})

We clean up before each test and once after the entire test suite:

// cypress/support/index.js

import './commands'

beforeEach(() => {
cy.resetDatabase()
})

after(() => {
cy.resetDatabase()
})

Populating the database with test data

This particular project is using factory_bot which turned out to be a good companion to Cypress.

Let's add an endpoint for creating data.

# lib/test_routes.rb

def test_routes
namespace :cypress do
delete 'cleanup', to: 'cleanup#destroy'

resource :factories, only: %i[create]
end
end
# app/controllers/cypress/factories_controller.rb

class Cypress::FactoriesController < ActionController::Base
def create
factory = FactoryBot.create(factory_name, factory_attributes)
render json: factory
end

private

def factory_name
params.fetch(:name)
end

def factory_attributes
params.fetch(:attributes).permit!.to_h
end
end

The idea is to send the factory name and attributes in the request body:

// cypress/support/commands.js

Cypress.Commands.add("factory", (name, attributes) => {
cy.request('POST', '/cypress/factories', {
name: name,
attributes: attributes || {}
}).as('test data')
})

This allows us to invoke factories from tests. For example:

describe('Login', () => {
it('is successful', () => {
cy.factory('user', {username: 'jane', password: 'janespassword'})

cy.visit('/')
cy.get('[data-cy=username]').type('jane')
cy.get('[data-cy=password]').type('janespassword')
cy.get('[data-cy=submit]').click()

cy.contains('Welcome back!')
})
})

Speaking about logging in, Cypress encourages you to "cheat" as much as possible in the test setup phase. (See Cypress best practices) Logging in using through the user interface is reserved for those tests that actually verify the login flow. Every other test can use a backdoor.

Login helper

# lib/test_routes.rb

def test_routes
namespace :cypress do
# ...
resource :sessions, only: %i[create]
end
end
# app/controllers/cypress/sessions_controller.rb

class Cypress::SessionsController < ActionController::Base
def create
sign_in(user)
render json: user
end

private

def user
if params[:username]
User.find_by!(username: params.fetch(:username))
else
User.first!
end
end
end

The corresponding command can be defined as follows:

// cypress/support/commands.js

Cypress.Commands.add("login", (username) => {
cy.request('POST', '/cypress/sessions', {
username: username
})
})

Now we can quickly login in tests with cy.login() (or cy.login('billie') to log in as 'billie').

Additional tips

You may have noticed that the /cypress/factories endpoint returns a JSON representation of created record. This makes it easier to inspect the data in the Cypress test runner interface (open the developer tools, and expand the response logged in the console).

It also allows you to use the returned data in the test, e.g.:

cy.factory('user').then((response) => {
cy.factory('appointment', {
user_id: response.body.id
})
})

Another thing that makes testing smoother is configuring the Rails server to reload code on every request in the test environment. By default code caching is enabled and speeds up the test suite. However, if you are also changing backend code while writing Cypress tests, you'd have to manually restart the server on every change. We use the configuration below to get the best of both.

# config/environments/test.rb

Rails.application.configure do
config.cache_classes = !ENV['CYPRESS_DEV']
end

During test driven development, we can get code reloading with CYPRESS_DEV=yes bin/test_server. On CI and when running tests locally, we omit the environment variable which leads to the default Rails test behaviour.

Insights from Finance 2.0

· Chanel Greco

Conference badge

This week I had the pleasure of attending Finance 2.0, which is the leading FinTech conference in Switzerland. In this post, I’ll be sharing the content of the conference from a software developer point of view.

The Customer is King

The slogan of the conference was “Facing a paradigm change: From CRM, the classic Customer Relationship Management, to CMR, a Customer-Managed Relationship.“ That sums up really well what most of the speakers addressed: the customer is in the driver’s seat and if the financial institutions do not cater to their needs, they will lose their reason of existence. This paradigm change has motivated the industry to be innovative and launch products that the users want to use.

The saying “The Customer is King” is no news for software developers. We know that if the app or software we are designing is not what the users want, they will simply not use it. With consumer loyalty on the decline, the financial industry has begun to focus on customer-centric tools just as we have been doing in software engineering.

Open Banking

The topic “Open Banking” was mentioned frequently. More and more banks are letting third-party companies (mostly startups) access their financial institution via open APIs to develop innovative tools. There was a panel about the security risks associated with open banking and how to deal with it.

Open Banking is an interesting topic. The panel discussion clearly showed that a market potential exists for innovative startups or software developers building services in collaboration with financial institutions. As a software agency with a lot of experience in simplifying complex processes, these are interesting prospects.

ICO’s and blockchain

I was rather surprised that there weren’t more speeches about the possibilities the blockchain technology offers for the financial industry. Instead, in a panel discussion titled  “ICO: A bubble or the future of funding?”, it was pointed out how crazy it is for startups collecting millions in investments without having produced anything except an unreadable white paper.

The underlying skepticism proofs that as a producer of digital products it’s not enough to simply groom oneself with the buzzword “Blockchain” to get into business with financial institutions. Only a valid business case can succeed in convincing potential customers.

Living innovation

I was thoroughly impressed by SIX Group and their innovation initiative. Here’s a large player in the financial industry not only talking about being innovative but actually living up to that claim. I particularly enjoyed the pitches from the winners of the SIXHackathon that took place the preceding weekend. The prototypes they developed in only 48 hours were very interesting and the level of (tech) talent from the team members was quite impressive.

Summary

The financial industry acknowledges that the times are changing and that it’s time to focus on the customer and their needs. Digital transformation is only one of the means to take this change into account, but it’s precisely what Simplificator is good at. These times are really exciting for us and we look forward to excelling our partners' businesses and making their customers happy.

Being a Software Developer Intern @Simplificator

· Chanel Greco

As I’m writing this blog post, I’m ending my 6-month internship at Simplificator as a software developer. A month ago I turned 34. Yes, you read correctly, at an age where most employees are looking to boost their careers, I decided to go back to square one and learn how to code. But why did I choose to do so?

I’ve always been intrigued by computers, software and computer games. At the tender age of 15, I had to decide, what job apprenticeship I wanted to take up: office clerk or information technology. Back then most information technology apprentices were boys, and I felt that I would feel out of place as the only girl in a class of 20+ students. As you can imagine, I decided to go for the office clerk education.

Fast forward fifteen years: I had just quit my job at a Zurich-based Start-up and had to decide, what I wanted to do next. Go back to managing IT projects and earning good money or invest time and money and learn how to build software? Play it safe or risk it?

I decided to listen to my heart and take a risk, and so I embarked on a journey to learn how to code.

I first started by teaching myself HTML and CSS and it turned out to be a straightforward thing to learn. The next step was JavaScript...not so straightforward. I learned just enough JavaScript and jQuery to get by, but I wasn’t happy with neither my learning pace nor my learning success. I was beginning to doubt my risky decision, and so I decided to give it one more shot: I enrolled in the Master21 Coding Bootcamp.

At this boot camp it just all fell into place, and that has a twofold reason: first of all, the fantastic instructor Rodrigo and second the programming language Ruby. It was the first time I had the feeling I could realistically reach my goal of learning to code.

Thanks to my boot camp instructor Rodrigo, I was approached by Simplificator employees and encouraged to apply for a job as a software developer. The multiple interviews I had at Simplificator were pretty tough, and it became apparent that I wasn’t yet at the level of a junior developer. Simplificator saw potential in me and offered me an internship as a software developer. Needless to say, I jumped at this opportunity to deepen my coding skills.

As a warm-up, I worked on my own little Ruby on Rails project and programmed a simple to do list. That work gave me the opportunity to both further my knowledge of Ruby and Ruby on Rails. I also learned how to use git and GitHub, Heroku, database management tools, IDE’s, etc.

I also got to do some frontend engineering on Simplificators own website.

To do list application
My to do list built with Ruby on Rails
 

The next (big) step was building a productive tool for Simplificator. “Burn Rate” is crucial in planning our work on the different projects we work on. Thanks to the custom calculation formula, the software indicates how much time we have to work the next four weeks on the various projects to fulfill the requirements.

When the first development cycle of “Burn Rate” ended and we implemented it in production, I was so happy: Here was a useful tool programmed by myself (ok, I got some help here and there).

The third and last step was working on a project for an existing customer. It was challenging and exciting at the same time, as I worked on implementing new features in a previously existing web app. It was very helpful for my Ruby knowledge as I was reading and trying to understand code, which was written by other developers.

As the end of my internship approached the question arose “Should I stay or should I go?”. Well, I decided to stay and here’s why:

  1. My internship made a developer out of me. But it will take time and lots of lines of code to make a good developer out of me.
  2. My team here at Simplificator is simply awesome. They truly made a point of teaching me well how to go about when developing. Each team member is very different but we harmonize really well together.
  3. My mentor Alessandro willingly shared his knowledge with me and always found the right words to motivate me. I’m sure I’ll learn a lot from him in the following years.
  4. I believe in the philosophy of Simplificator:
    • Love what you do
    • Collaborate closely
    • Keep it simple
    • Dare to question
    • Get things done
  5. I’m thankful for the chance Simplificator gave me.
  6. I love playing foosball with my colleagues.

Was it worth going back to square one at 34 years of age? Yes, it was! Was it easy? Not at all. But aren’t the difficult things the most rewarding?

Fussball
Enjoying a break with my colleagues

Use a Raspberry Pi 3 as an access point

· Mario Schüttel

raspberry-pi-logo

Raspberry Pis are awesome [citation needed].

This post is about how to setup a WiFi with a Raspberry Pi 3. It describes what packages you have to install and one example is shown how to configure them. In the end you will have an Raspberry Pi 3, which is connected through ethernet to the internet. The Pi provides an SSID and takes care that the traffic between WiFi and Ethernet is forwarded.

This tutorial basically follows the instructions on http://elinux.org/RPI-Wireless-Hotspot, except that it uses dnsmasq instead of udhcpd.

Steps

Operating system

Download and install an operating system for the Raspberry Pi. I used "Raspbian" and followed this description:

https://www.raspberrypi.org/documentation/installation/installing-images/mac.md

Before you unmount the flashed card, create a file named ssh in the boot segment on the disk. Otherwise you won't be able to SSH into the Raspberry Pi.

Installations

Connect the Pi to your local network (through ethernet), search for the little rascal (i.e. using nmap) and connect to it via ssh.

When logged in, you will have to install at least 2 packages: dnsmasq and hostapd. I always love to have vim, so here's what I did:

sudo apt-get update
sudo apt-get install vim
sudo apt-get install dnsmasq
sudo apt-get install hostapd

Configure the wlan interface

Now, let's edit the iface wlan0 part in /etc/network/interfaces, make sure it is static and has following properties:

allow-hotplug wlan0
iface wlan0 inet static
address 10.0.0.1
netmask 255.255.255.0
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

Behold, that I used the address 10.0.0.1 as static IP. We will have to use the same IP for the DHCP configuration.

At this point you should quickly restart the networking service.

sudo service networking restart

ifconfig wlan0 should then show the applied changes on in the wlan0 interface.

Configure DNSmasq

The Pi will have to manage the clients IP address (DHCP) on the wlan0 interface. I used DNSmasq for the DHCP server, but it should work fine with any other DHCP servers.

However, let's edit /etc/dnsmasq.con

domain-needed
bogus-priv
interface=wlan0
listen-address=10.0.0.1
dhcp-range=10.0.0.2,10.0.0.254,12h
dhcp-option=option:router,10.0.0.1
dhcp-authoritative

Note that the Pi's static IP address is used for listen-address and dhcp-option=option:router. For more information about that, consider reading http://www.thekelleys.org.uk/dnsmasq/doc.html. ;-)

Portforwarding (route wlan0 to eth0)

The next step affects iptables. I am no expert in this, so I basically just copy pasted that stuff and ensured that the in -i and out -o parameters made sense.

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT

In a nutshell, it allows that general traffic/communication is allowed between the interfaces wlan0 (wireless) and eth0 (ethernet). In order that the iptables rules apply immediately, you'll have to do this:

sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"

In order that the iptables rules are considered after reboot, edit /etc/sysctl.conf, and uncomment this line:

net.ipv4.ip_forward=1

Finally persist the iptables rules, otherwise they get truncated after reboot. I used a package iptables-persistent which persists the rules right during installation which is pretty convenient.

sudo apt-get install iptables-persistent

Configure the access point

Now it get's interesting. We can create our own SSID and define a password. Therefore create /etc/hostapd/hostapd.conf and paste and save this:

interface=wlan0 driver=nl80211
ssid=SIMPLIFICATOR-WIFI
hw_mode=g
channel=6
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=YOUR-INCREDIBLY-SECURE-PASSWORD
wpa_key_mgmt=WPA-PSK
#wpa_pairwise=TKIP  # You better do not use this weak encryption (only used by old client devices)
rsn_pairwise=CCMP
ieee80211n=1          # 802.11n support
wmm_enabled=1         # QoS support
ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]

Let's connect the above config to the default hostapd config, edit /etc/default/hostapd and make sure DAEMON_CONF is uncommented and points to the config file.

DAEMON_CONF="/etc/hostapd/hostapd.conf"

Services (hostapd & dnsmasq)

Lastly, let's restart the services and enable them, so that the start automatically on boot.

sudo service hostapd restart
sudo service dnsmasq restart
sudo update-rc.d hostapd enable
sudo update-rc.d dnsmasq enable

That's it

You should now see a WiFi named SIMPLIFICATOR-WIFI and connect to it using the passphrase YOUR-INCREDIBLY-SECURE-PASSWORD, or whatever values you have given it.

Insights

While writing the blog post I had several insights: