Ruby, code you enjoy coming back to

Few languages let you express an idea as elegantly and clearly as Ruby. We have used it since founding 10KB in 2013 and still do a lot of ongoing development in it. Around half our projects now use TypeScript, but our love of Ruby has never gone away. And when the Ruby on Rails approach fits your project, you can build something good remarkably quickly.

  • Part of our work since 2013

  • Elegant code that reads close to everyday language

  • Fast development with Rails conventions

Bauke and Roland working on software together at 10KB.

Ruby at 10KB

A language we enjoy thinking in

When Ewout and Roland founded 10KB together in 2013, most of their development experience was in PHP. Rails felt like a more mature framework, and Ruby's standard library was more extensive and pleasant to use. But perhaps the biggest attraction was how beautifully you could write code in it.

That enjoyment has stayed with us. 5.times reads as “five times”. With Rails, 3.days.ago is simply “three days ago”. There is less technical notation between you and the intent. That might sound like a concern for developers, but when software keeps evolving for years, understandable code matters to the client too.

10KB developers looking at application code together.

Why we use Ruby and Rails

A pleasure to write and maintain

Ruby lets you write code that almost reads like a sentence. Going through a list, adding amounts or naming a condition often takes very little extra notation. We find that one of the language's best qualities. Your attention goes to what the code does, which also helps the colleague who works on it next.

We can extend Ruby with terms that belong to an application. A reminder plan might literally say: email after three days, call after seven. A small domain-specific language, or DSL, makes recurring rules easy to read and change. Further down, we show how little code this takes.

Rails has an established approach to forms, database access, email and background jobs. The framework determines how those parts work together. When that suits your application, we can spend less time on setup and get to work on the features you need.

The code shows the intent

Ruby lets you write code that almost reads like a sentence. Going through a list, adding amounts or naming a condition often takes very little extra notation. We find that one of the language's best qualities. Your attention goes to what the code does, which also helps the colleague who works on it next.

How we decide

Does your project fit the Rails way?

Rails is opinionated: it has firm ideas about how to build a web application. Those conventions are a real advantage when your project fits. A portal with accounts, forms, overview screens and recurring workflows can take shape quickly.

If we need to depart from that approach in many places, the benefit diminishes. We spend more time on exceptions, and another language or framework may fit better. We therefore look at the interactions you need, existing systems and the team that will maintain the application.

Static type checking matters too: feedback about data types before code runs. Ruby has tools for this, but in our work we find them less developed than TypeScript's. That is one consideration alongside development speed, readability and project fit. The fact that around 50% of our projects now use TypeScript does nothing to diminish the pleasure we take in writing Ruby.

Discuss which approach fits your project
Two 10KB developers discussing a technical decision.

In our work

Ruby in business applications

For LiVvE, we built a Rails application for homeowners' association management, with accounting, document processing and a portal for managers and members. Recurring contributions and reminders are handled in the same environment.

At SGI Compliance, we develop Werkplanner with configurable forms and project documents. At Smartfile, we improved authorisation, tests and deployments for existing Rails software. Ruby is part of our work both when building business applications and when developing them further.

See LiVvE in practice
Bauke and Roland looking at software on a monitor together.

The structure behind Rails

Model, View, Controller: each has a job

Rails helped popularise MVC among web frameworks. The pattern already existed, but Rails made it a recognisable starting point: data and business rules, presentation and request handling each have a place.

Take a customer opening an invoice. The Controller receives the request and asks for the right invoice. The Model holds the data and rules, such as how the total is calculated. The View turns that into the screen the customer sees.

A change to the invoice's appearance therefore need not change its calculation. And an updated calculation need not be rewritten for every screen. That shared structure helps us find where a change belongs.

MVC in Rails: a request reaches the Controller, which works with the Model and renders the View. The View provides the user's screen.

Try reading it aloud

Five times? Just 5.times

You could create a counter, increment it and check whether you are done. Ruby also lets you simply write 5.times. The block that follows says what should happen five times. And sum adds a list of amounts.

That is Ruby's appeal in a few lines: the code shows the intent. Here we create five invoice names and add amounts in whole euros.

ruby
# Ruby almost reads like a sentence
invoices = []

5.times do |number|
  invoices << "Invoice #{number + 1}"
end

puts invoices
# Invoice 1, Invoice 2, ... Invoice 5
# Each name appears on its own line.

amounts = [20, 35, 45]
puts amounts.sum
# 100 euros, without maintaining a counter yourself.

Rails builds on that idea

Three days ago: 3.days.ago

Active Support, part of Rails, adds words such as days and ago. You can write “three days ago” without calculating seconds yourself. 2.weeks.from_now does the same for a point in the future.

Here we use it to check whether an invoice is more than three days old. 5.times is part of Ruby itself; the time expressions come from Active Support. You can also use that library outside a full Rails application.

ruby
# Time in everyday words
require "active_support/all"

# Active Support adds these time expressions.
cutoff = 3.days.ago
issued_at = 5.days.ago

if issued_at < cutoff
  puts "This invoice is over three days old."
end

# A point in the future reads naturally too.
next_review = 2.weeks.from_now
puts next_review.to_date
# The date two weeks from now.

# No bare numbers with units you have to guess.
# 3.days is a duration; 3.days.ago is a point in time.

The words of your application

Email after three days, call after seven

We can take that readability further ourselves. A DSL is a small language for a particular subject. Here we make after 3.days, via: :email a valid rule in a reminder plan. It is still ordinary Ruby code; we supply the words and their meaning.

The class defines what after does. Below it, the plan reads almost like a work instruction. Changing a delay then takes a change in one clear place. This example only describes the steps; it does not schedule jobs or send messages.

ruby
# Our own language for reminders
class ReminderPlan
  attr_reader :steps

  def initialize(&rules)
    @steps = []
    instance_eval(&rules)
  end

  def after(delay, via:)
    @steps << { delay: delay, via: via }
  end
end

# This is our own DSL, written in ordinary Ruby.
plan = ReminderPlan.new do
  after 3.days, via: :email
  after 7.days, via: :phone
end

# Inspect the rules we have recorded.
plan.steps.each do |step|
  days = step[:delay].in_days.to_i
  puts "After #{days} days: #{step[:via]}"
end
# After 3 days: email
# After 7 days: phone

# The delays are relative to the start of the plan.
# Sending messages and scheduling jobs belong elsewhere.
ruby
# Ruby almost reads like a sentence
invoices = []

5.times do |number|
  invoices << "Invoice #{number + 1}"
end

puts invoices
# Invoice 1, Invoice 2, ... Invoice 5
# Each name appears on its own line.

amounts = [20, 35, 45]
puts amounts.sum
# 100 euros, without maintaining a counter yourself.

# Time in everyday words
require "active_support/all"

# Active Support adds these time expressions.
cutoff = 3.days.ago
issued_at = 5.days.ago

if issued_at < cutoff
  puts "This invoice is over three days old."
end

# A point in the future reads naturally too.
next_review = 2.weeks.from_now
puts next_review.to_date
# The date two weeks from now.

# No bare numbers with units you have to guess.
# 3.days is a duration; 3.days.ago is a point in time.

# Our own language for reminders
class ReminderPlan
  attr_reader :steps

  def initialize(&rules)
    @steps = []
    instance_eval(&rules)
  end

  def after(delay, via:)
    @steps << { delay: delay, via: via }
  end
end

# This is our own DSL, written in ordinary Ruby.
plan = ReminderPlan.new do
  after 3.days, via: :email
  after 7.days, via: :phone
end

# Inspect the rules we have recorded.
plan.steps.each do |step|
  days = step[:delay].in_days.to_i
  puts "After #{days} days: #{step[:via]}"
end
# After 3 days: email
# After 7 days: phone

# The delays are relative to the start of the plan.
# Sending messages and scheduling jobs belong elsewhere.

Ruby and Rails keep evolving

From our first project to today

We have worked with Ruby since 2013. In that time, the language, development tools and ways of deploying Rails applications have changed considerably.

2013

10KB

We start 10KB with Ruby

Ewout and Roland found 10KB. After working in PHP, they choose the mature Rails approach and the pleasure of elegant, readable Ruby code.

2020

Ruby 3 gives types a place

Ruby 3 introduces RBS for describing types and TypeProf for analysing code. Ruby stays dynamic but gains more tools for understanding data types before execution.

2021

Rails 7 embraces Hotwire

Hotwire lets interactive screens be built largely from HTML on the server. A separate frontend application is no longer necessary for every interactive page.

2023

Ruby 3.3 improves YJIT

YJIT compiles frequently used Ruby code into machine code while the application runs. Ruby 3.3 improves the compiler's performance and memory use. The benefit to an application depends on its workload.

2024

Rails 8 covers more of deployment

Rails 8 includes Kamal 2 for deployments and Solid Queue for background jobs by default. The established Rails approach extends further from writing code to running the application.

Ruby and Rails at other companies

From snowboard shop to commerce platform

Shopify started in 2004 with two developers and an early Rails release. Its predecessor, snowboard shop Snowdevil, was built in under four months according to the Rails announcement at the time. Founder Tobias Lütke attributed that productivity in part to Rails.

That is the attraction when the fit is right: a small team can quickly build a working product and develop it further. At Shopify, that became a platform on which other entrepreneurs could start their shops.

AI-generated square atmospheric image of a merchant packing a parcel beside a laptop showing order management, accompanying the Shopify story.

Ruby and Rails at other companies

A first beta in three months

GitHub began in October 2007 as an evening and weekend project. Co-founder Tom Preston-Werner described how Chris Wanstrath built the Rails application while he worked on the Git integration and interface. Three months later, the private beta opened.

That division of work illustrates how Rails can help at the start: an existing foundation for the web app, with room for the team's own product idea. They could offer something useful early and develop it further with users.

AI-generated square atmospheric image of two developers reviewing code together, accompanying the GitHub story.
AI-generated square atmospheric image of a merchant packing a parcel beside a laptop showing order management, accompanying the Shopify story.AI-generated square atmospheric image of two developers reviewing code together, accompanying the GitHub story.

Ewout

Contact person: Ewout

Does Ruby on Rails suit your plans?

Want to build a first version quickly or develop an existing Rails application further? Talk to Ewout. We can look at your workflows, your team and how well the Rails approach fits.

CONTACT

Get in touch with us

Have a question or want to discuss your software? Leave your details and we will get back to you soon.