My plan with this site was to see how little I could get away with. Call it an exercise in developer minimalism.

Libraries

Sinatra handles the incoming web requests with simple handlers:

get "/*" do
  slug = params[:splat].first

  cache slug do
    post = PostStore.find(slug)

    return not_found unless post

    PostView.new(post: post).call
  end
end

PostStore is a simple class with a handful of methods that use pg directly. I'm using connection_pool although I suspect I could get away without it.

Views are built and rendered using Phlex because it's the Ruby view library we've all been waiting for 😄

class PostView < Phlex::HTML
  include ViewHelpers

  def initialize(post:)
    @post = post
  end

  def template
    render Layout.new(title: @post["title"]) do
      div(class: "body") do
        body
      end
    end
  end

  def body 
    markdown @post["body"]
  end
end

The output from each URL is cached so most requests don't even hit the database.

The views render markdown with Red Carpet and rouge handles the syntax highlighting.

For development, I'm using rerun with rackup for the dev server and rspec with capybara for testing.

Server

I have a VPS from Ionos running nginx and passenger.

SSL certs are from Let’s Encrypt.

The setup and maintenance is manual which is a breath of fresh air after years of k8s and docker. Manually editing nginx configs via ssh gives me a strange sense of nostalgia.

Deploying

Deployment is a 2 line script using rsync:

rsync -av --exclude={'.env','.git','cache'} . user@server:/path/to/site/
ssh user@server -T "rm /path/to/site/cache/*.html && touch /path/to/site/tmp/restart.txt"

The app deploys in seconds.


Stripping everything back to basics has had some fun results:

Questioning everything has lead to simplifications I didn't expect. Normally I would naturally start to architect - with b;r I don't even really have a folder structure.

This has meant that the parts of the app are very clear at the top level. There are no controllers or models or actions - it's clear - post_view.rb has the... erm... "post view".

I can also postpone certain things as I’m the only one using it. Lack of certain validations will frustrate me eventually - when they do, I’ll find the smallest change to add them.

Deploying is a dream - I picked rsync without really thinking about it, but the first time I deployed it genuinely surprised me. It's obvious of course - it's just copying files - but still 😍

I doubt this approach scales but that wasn't really the point.


Inspiration

Listening to Derek Sivers on Remote Ruby #216 sparked this all off.