How to write modular code

Or: How to avoid and refactor spaghetti code

Please note that I tried to keep the examples small. The effects of the methods in this card are of course much more significant with real / more complex code.

What are the benefits of more modular code?

Code is written once but read often (by your future self and other developers who have to understand it in order to make changes for example). With more modular code you reduce the scope of what has to be understood in order to change something. Also, naming things gives you the opportunity t...

Rails: Rest API post-mortem analysis

This is a personal post-mortem analysis of a project that was mainly build to provide a REST API to mobile clients.

For the API backend we used the following components:

  • Active Model Serializer (AMS) to serializer our Active Record models to JSON.
  • JSON Schema to test the responses of our server.
  • SwaggerUI to document the API.

It worked

The concept worked really good. Here are two points that were extraordinary compared to normal Rails project with many UI components:

  • Having a Rails application, that has no UI components (only...

Checklist: Using Carrierwave in a Rails project

This checklist should help you to check edge cases that are not part of the default Carrierwave configuration.

Always convert and strip user-provided images to sRGB

Debugging image color profiles is hard. You can't trust your eyes in this matter, as the image rendering depends on multiple factors. At least the operation system, browser or image viewer software and monitor influence the resulting image colors on your screen.

When we offer our users the possibility to upload images, they will most likely contain tons of EXIF metadata and sometimes exotic color profiles like eciRGB. We want to get rid of the metadata, as it might contain sensitiv...

Defining new elements for your HTML document

Browsers come with a set of built-in elements like <p> or <input>. When we need a new component not covered by that, we often build it from <div> and <span> tags. An alternative is to introduce a new element, like <my-element>.

When a browser encounters an unknown element like <my-element>, the browser will proceed to render <my-element>'s children. The visual rendering of your page will not be affected.

If you care about their HTML being valid, your new element should contain a dash character (-) to mark it as a *custom el...

Rspec 3: what to do when `describe` is undefined

When tests might not run with skipping RSpec in the RSpec.describe failing with the error undefined method 'describe' for main:Object this card will help you out!

In RSpec 3 the DSL like describe is exposed globally by default. Therefore it is not necessary to write Rspec.describe.

However, there is a config option to disable this beavior, which also disables the old should-syntax:

RSpec.configure do |config|
  config.disable_monkey_patching!...

Resources for working with the Youtube API

You can use the Youtube API to get data from youtube. Here are some resources and some things that are good to know.

You need to create an API key and each request will cost a certain amount of Request-Points (depending on the kind of query).

It may help to understand youtube's domain model before starting.

It's best to just try out your requests in the browser to see what you will get.
A request can look like this (note that you have to replace the playlis...

Defining "partials" in pure HTML without additional rendering helpers

A while ago I tweeted a thread about how a small JavaScript snippet, one that can fit in a single tweet in fact, can be used to allow defining custom elements purely in HTML. This post will expand on the idea, show how the snippet works, and argue for why you might want to actually use this.

A nice trick that lets you define "partials" in HTML without any additional rendering technology on the server or client.

Pattern: Disabling a certain feature in tests

There is a kind of features in web applications that hinder automated integration tests. Examples include cookie consent banners or form captchas. Clearly, these should be disabled so you do not have to explicitly deal with them in each and every test (like, every test starting with accepting the cookies notice). On the other hand, they must be tested as well.

A good feature disabling solution should therefore meet these requirements:

  • The feature is generally disabled in tests. A test does not need to do anything manually.

  • It is *...

Can I Email: Check what styling email clients support

The french Tilt Studio built a caniuse clone for email clients.

Note that while checking styling support helps using (or not using) certain features, it cannot substitute for checking the actual rendering in real clients. Make sure you follow Designing HTML Emails.

ActiveSupport includes Timecop-like helpers

ActiveSupport (since 4.1) includes test helpers to manipulate time, just like the Timecop gem:

  • To freeze the current time, use freeze_time (ActiveSupport 5.2+):

    freeze_time
    
  • To travel to a specific moment in time, use travel_to:

    travel_to 1.hour.from_now
    

    Important

    When freezing time with #travel_to, time will be frozen (like with freeze_time). This means that your application can't detect passage of time by using Time.now.

  • To travel a re...

Capybara: Execute asynchronous JavaScript

Capybara provides execute_script and evaluate_script to execute JavaScript code in a Selenium-controlled browser. This however is not a good solution for asynchronous JavaScript.

Enter evaluate_async_script, which allows you to execute some asynchronous code and wait until it finishes. There is a timeout of a couple of seconds, so it will not wait forever.

Use it like this:

page.evaluate_async_script(<<~JS)
  let [done] = arguments
  doSomethingAsynchronous().then(() => {
    done() // call this to indicate we're done
  })
J...

Rails: Verify the CSRF token

Rails uses a CSRF token in forms and AJAX requests to verify a user request. Internally it compares the injected CSRF token of the form data with the CSRF token in the encrypted user session. To prevent SSL BREACH attacks, the CSRF token from the form data is masked.

To better debug issues, when these tokens do not match, it is useful to unmask the CSRF token from the form da...

Guidelines for Pull Requests and Code Reviews

Projects with more than one developer should always consider to enforce code review even for small changes to improves the overall code health of the system. Here are some guidelines that can help you to accomplish this task.

Github

How to write the perfect pull request

Google

Google's Engineering Practices documentation
Modern Code Review: A Case Study at Google

Though...

A collection of useful design resources for developers

This collection contains some useful design resources for developers. Many of them were mentioned in the Refactoring UI tutorials.

Tutorials

Checking database size by row count

As an application exists, data accumulates. While you'll be loosely monitoring the main models' record count, some supportive database tables may grow unnoticed.

To get a quick overview of database table sizes, you can view the row count like this:

PostgreSQL

SELECT schemaname,relname,n_live_tup 
FROM pg_stat_user_tables 
ORDER BY n_live_tup DESC
LIMIT 12;

 schemaname |                    relname                     | n_live_tup 
------------+------------------------------------------------+------------
 public     | images...

Rails: Invoking a view helper from the console

There are a few ways to access view helpers from the Rails console. The easiest way is the helper shortcut:

helper.translate 'i18n.string'
helper.your_helper_method

If the desired helper renders a view template, you need this setup:

view_paths = Rails::Application::Configuration.new(Rails.root).paths["app/views"]
av_helper = ActionView::Base.new(view_paths).extend YourHelperModule

av_helper.your_helper_method

Rails routing: Using constraints to avoid "Missing template" errors

You can use constraints in your routes.rb to avoid getting ActionView::MissingTemplate errors when wrong routes are called. Instead, the user will see a 404.

If you want multiple routes to use the same constraint you can use the block syntax:

constraints(format: 'html') do
  resources :pages
  resources :images
end

If you want constraints only on certain routes, you can do:

get '/users/account' => 'users#account', constraints: { format: 'html' }

Tip

You can also avoid this error type through [format con...

Using CSS transitions

CSS transitions are a simple animation framework that is built right into browsers. No need for Javascript here. They're supported by all browsers.

Basic usage

Transitions are used to animate the path between to property values. For example, to let the text color fade from red to green on hover, the following SASS is used (shorthand syntax):

.element
  color: red
  transition: color .1s
  
  &:hover
    color: green

This tells the browser "whenever the color of an .element changes...

Joining PDFs with Linux command line

There are several ways to merge two (or more) PDF files to a single file using the Linux command line.

If you're looking for graphical tools to edit or annotate a PDF, we have a separate card for that.

PDFtk (recommended)

PDFtk is a great toolkit for manipulating PDF documents. You may need to install it first (sudo apt install pdftk).
Merging multiple files works like this:

pdftk one.pdf two.pdf cat output out.pdf

Unlike pdfjam, PDFtk should not mess with page sizes but simply joins pages as they are.

...

Controlling how your website appears on social media feeds

When a user shares your content, a snippet with title, image, link and description appears in her timeline. By default social networks will use the window title, the first image, the current URL and some random text snippet for this purpose. This is often not what you want.

Luckily Facebook, Twitter, etc. lets you control how your content appears in the activity streams. They even have agreed on a common format to do this: OpenGraph <meta> tags that go into your HTML's <head>:

<meta property="og:url" content="http://start.m...

Unpoly: Showing the better_errors page when Rails raises an error

When an AJAX request raises an exception on the server, Rails will show a minimal error page with only basic information. Because all Unpoly updates work using AJAX requests, you won't get the more detailled better_errors page with the interactive REPL.

Below is an event listener that automatically repeats the request as a full-page load if your development error shows an error page. This means you get...

How to inspect the HTML of an email in Thunderbird

Inspecting the source of an email does not always reveal the plain HTML source, but some encoded byte mess. In order to inspect the HTML anyways, you can use a little trick:

While composing a message, select all (Ctrl + A), then navigate to Insert > HTML on the message window.

If you need to inspect a received message, hit "Reply" to turn it into composition mode.

Jasmine: using async/await to write nice asynchronous specs

Jasmine has long standing support for writing asynchronous specs. In days gone by we used the done callback to achieve this, but these days it is possible to write much more readable specs.

Async specs

As a first example, say we want to check that some form disables the submit button while working.

// bad (how we used to do it)

beforeEach(() => {
  this.form = setupMyForm()
  this.submitButton = findTheSubmitButton()
})

it('disables the submit button while working', (done) => {
  expect(this.submitButton.disabled).toBe(false)
...