“...I've been working since 2008 with Ruby / Ruby on Rails, love a bit of Elixir / Phoenix and learning Rust. I also poke through other people's code and make PRs for OpenSource Ruby projects that sometimes make it Currently working for GenieBelt who are based in Copenhagen, Denmark ...”

Rob Lacey
Senior Software Engineer, Copenhagen, Denmark

Redis::CommandError: MISCONF Redis

Ok that’s annoying

265) returns a thing
       Failure/Error: raise reply if reply.is_a?(CommandError)
       
       Redis::CommandError:
         MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.

Ok, just upgraded brew earlier, it’s probably upgraded and restarted Redis. Thanks for a find on the Googles https://gist.github.com/kapkaev/4619127

Robs-MBP:sard rl$ redis-cli
127.0.0.1:6379> config set stop-writes-on-bgsave-error no
OK
127.0.0.1:6379> quit

No more moaning from Redis.

New Project

I’m embarking on a new project this month, the plan is to have it live within the month. The purpose of the project is to learn Elixir because I want to play with new toys (ok, it’s not new anymore). I’ve found the only way to really learn is to create something, you can read a book but unless you apply your knowledge to something meaningful it’s not valuable. Not to mention that you can read all you want in a book but you never see the real world issues with your new toys unless you try something, break it, fix it, break it again. It’s like breaking in some new shoes. And then your dad goes and writes your name on them.

So, I’m passionate about music. I have a stupid sized collection of T-Shirts. I’m going to build a Band Shirt Archive. I guess a bit like the wiki part of Discogs , but first I’m going to populate it with all of my T-Shirts. Simple. A database of Artist / Band names, Photos (both stock and real life). Well, if it was Rails, I’d be up and running with a day (it would be messy) or so but I’m familiar with all of the usual suspects. ActiveRecord, AWS, file uploads with Paperclip, Authentication with Devise all that gubbins. But I need to translate all of that knowledge into a new Paradigm. Everything I’ve written in Ruby in the last 10 years has sat me squarely in the realm of ‘everything is an object’, now I need to break out and view this all through a different window.

So, gathering my tools. What do I need. I’ve got a whole host of books. I have tinkered with Phoenix a little but it was the pre-1.4 after which some things have changed, enough to warrant another edition anyway.

https://pragprog.com/titles/phoenix14/programming-phoenix-1-4/
https://pragprog.com/titles/wmecto/programming-ecto/
https://pragprog.com/titles/sbsockets/real-time-phoenix/


https://pragprog.com/titles/elixir16/programming-elixir-1-6/
https://pragprog.com/titles/cdc-elixir/learn-functional-programming-with-elixir/
https://pragprog.com/titles/lhelph/functional-web-development-with-elixir-otp-and-phoenix/

Kat also bought me Programming WebAssembly with Rust so I need to include some Rust-y experiment in here too.

Is MiniZinc better than writing my constraint solution in Ruby / Python

% Basic MiniZine example
var 2..4: x;
var 1..2: y;
constraint x + y < 7;
solve satisfy;

Bundler is moaning

Seems dashes are outlawed now. Will fix that…

00:45 bundler:config
      01 $HOME/.rbenv/bin/rbenv exec bundle config --local deployment true
      01 Your /home/deploy/.bundle/config config includes `BUNDLE_BUILD__OR-TOOLS`, which contains the dash character (`-`).
      01 This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.
      01 Please edit /home/deploy/.bundle/config and replace any dashes in configuration keys with a triple underscore (`___`).

Ok, it’s true

deploy@li762-169:~$ cat .bundle/config 
---
BUNDLE_BUILD__OR-TOOLS: "--with-or-tools-dir=/usr/local/bin/or-tools"

Twiddle

deploy@li762-169:~$ cat .bundle/config 
---
BUNDLE_BUILD__OR___TOOLS: "--with-or-tools-dir=/usr/local/bin/or-tools"

And it’s stopped moaning…

00:25 bundler:config
      01 $HOME/.rbenv/bin/rbenv exec bundle config --local deployment true

Measuring Success

Much of the work I’ve been doing over the past 10 years has been taking older systems and keeping them current. My first Rails gig was to move hundreds of thousands of users and their services from two older systems effectively white labelled brands written in Perl (CGI) into one new stonking system under just one of those brands. You have to keep your eye on the ball, technology changes and you have to keep up. Anyone still doing web development with Perl are probably thin on the ground now products will have died and the people that wrote them moved onto better things.

Hell, even when you choose a language like Ruby things change all the time and code needs nurturing. This is often burying my head in code quality improvements both in terms of legibility and performances. You make code more legible and when you do you spot things that can turn a controller action from making stupid amounts of database queries to 2 queries for example. As a side-note I sometimes get so buried in these things that when it comes to doing the simple stuff I have to refresh things I haven’t touched in a year. Like how the hell do I set up a collection_select. That aside, this work to some might seem monotonous but I love it.

But as with many refactoring and upgrading tasks, its hard to prove it’s worth to your average outsider. Yeah, I worked really hard on this thing guys and if you look hard enough you’ll see there is less code and less network traffic too and from our DB server. Blank faces.

Ok, that’s not strictly true we have a great team at SARD who understand that we’re not just sitting pretty drink cups of tea and kicking a can down the street. It’s important to know when you’ve made successful leaps in productivity and that has had a purpose. In my case my last piece of work was a means to an end to unlock a blocked upgrade.

It is however intensely satisfying to see a measure of success and today that was to show that on this application the average request from is down from 1500ms to 800ms. Boom.

Always end with a graph with Caramel brown in it.

load all of the stuff

Loading console and half of your models aren’t defined? They won’t necessarily be just to help boost boot up time.

Rails.application.eager_load!

This will load everything.

Elixir Error Reporting is pretty good huh?

As much as Elixir feels quite alien at times. The error reporting is really very thorough.

iex(4)> c = IslandsEngine.Coordinate.new(1,1)
{:ok, %IslandsEngine.Coordinate{col: 1, row: 1}}
iex(5)> Island.new(:square, c)               
** (FunctionClauseError) no function clause matching in IslandsEngine.Island.new/2    
    
    The following arguments were given to IslandsEngine.Island.new/2:
    
        # 1
        :square
    
        # 2
        {:ok, %IslandsEngine.Coordinate{col: 1, row: 1}}
    
    Attempted function clauses (showing 1 out of 1):
    
        def new(type, %IslandsEngine.Coordinate{} = upper_left)
    
    (islands_engine 0.1.0) lib/islands_engine/island.ex:7: IslandsEngine.Island.new/2
iex(5)> {:ok, c } = IslandsEngine.Coordinate.new(1,1)
{:ok, %IslandsEngine.Coordinate{col: 1, row: 1}}
iex(6)> c
%IslandsEngine.Coordinate{col: 1, row: 1}
iex(7)> Island.new(:square, c)                       
{:ok,
 %IslandsEngine.Island{
   coordinates: #MapSet<[
     %IslandsEngine.Coordinate{col: 1, row: 1},
     %IslandsEngine.Coordinate{col: 1, row: 2},
     %IslandsEngine.Coordinate{col: 2, row: 1},
     %IslandsEngine.Coordinate{col: 2, row: 2}
   ]>,
   hit_coordinates: #MapSet<[]>
 }}

I initially thought that an aliased %Coordinate{} could not be pattern matched against an %IslandEngine.Coordinate{}. Wrong. it can’t be pattern matched against a tuple. Wally.

Imposter Syndrome

I am not an imposter.

A small amount of history. My first Ruby / Rails / Dev gig was for Advantage Interactive working on lcn.com They are still my domain registration provider and if you look really really hard probably none of my work is left on that site anymore. But times change. The company re-located in 2008 and I found myself needing to look for something else. We gotta eat and we’ve got kittens to feed too.

I got an interview for a company that sold e-commerce solutions to a number of clients and having worked with OSCommerce for a years with PHP and a grounding on a domain registration and web hosting service which had a cart and payment processing and the like I thought it was a good fit. As soon as I got there I was paired up with another developer and set to work on an address book application as a coding challenge. I did my homework and I specifically used the new kid on the block ‘nested routes’ yup know the ’ole /products/1/attributes/17903 malarky.

resources :products do
  resources :attributes
end

Ok, I probably thought I was being pretty smart. What I didn’t expect was that my pair was pretty patronising, he didn’t like this solution for the address book which had a parent object and a multiple child objects so ideal for this scenario. He started to prompt me to find a different solution and he said very slowly so I could hear him clearly “…maybe use a session…?”. He meant instead of using /products/1/attributes/17903. That I should store the product_id in a session when accessing the child object. Effectively.

# set product_id in session
session[:product_id] = 1
# visit
GET /attributes/17903
# and then grab record 
Attribute.where(product_id: session[:product_id], id: params[:id])

To me this is crazy, why in the hell would you use state to manage this. That’s not what a session is for, a session is for having a pretty good try at faking state with HTTP which is basically stateless. So we can maintain logging into a system across multiple requests for example. I just didn’t get his reasoning and we butted heads. “Why would we do that?”. Which on reflection he read as “Why would we do that because I am desperately out of my depth, dude”. He was insistent.

We moved on from the code interview which I had clearly failed in his eyes because I clearly didn’t understand what a session was. I know what a session is. We entered a big room with an oval table, and I was met with another developer. They slouched across the table and told me a bit about the company and that they were migrating a ton of clients over to Rails. I asked “Why Ruby?”, because I wanted to know their reasoning for migrating at this time. If you are going to up and move everything at some significant cost then there has to be a motivation right, something they can’t resolve and can only be resolved longer-term by moving everything over? They misunderstood my question and started telling me how great Ruby was. Dudes I have been working with Ruby full-time for 3 years. I’m not an idiot. But they treated me like one. And eventually said “You’re clearly not a Developer”. Honestly, I was at this point angry because you can’t argue with people who have made up their mind without really taking the time to understand who I was and what experience I had. They didn’t even ask me what I’d been working on.

This is the first time I’d been made to feel bad for not knowing stuff that I do actually know. It’s hard to express yourself when you’re up against confident (or indeed arrogant) people, outward confidence in a meeting room from a lesser experienced person can trump years of experience and that’s crazy. I had clearly not made it to the next stage and I wasn’t likely to work with them anyway given the vibe I got from them.

I continued to look around for work. I had multiple recruiters put me forward for things. I did a code test for Reevoo and got a callback from the recruiter saying that they were impressed with my test and they’d like to move forward, except. “We heard you had a bad interview with insert company>”. What? There are times when you are paranoid that people might not like you or might be talking behind your back, and often you’re imagining it. But no…people had actually been talking behind my back. A recruiter completely unconnected to the company I had interviewed for had information on me and a black mark had been put against my name. How does that work? Who the actual, WTF??? I explained my experience to the recruiter and we went back and forth many times on it. I had to move on sadly and look elsewhere. Not because I was a bad developer but someone had made their mind up and told others they should question my ability even if you had a pleasing code test. Is this what they call Gatekeeping, did they think they were better or that I was just a pretender to the throne?

It’s difficult not to be bitter about such things, I remember all of this pretty clearly and it was a difficult time. Fortunately going the Recruiter route is not the only way. I had to find work pretty quickly and I wasn’t going to continue working in Stevenage with a 3 hour each way journey. Fortunately I met Zach, via a forum and joined PledgeMusic about a month later for 9 years and 11 months. ( we didn’t make it to 10 :( ) and from that first day I never felt like I wasn’t good enough, like everyone else I’ve written bad code, broken things, managed full-time work and at least 6 long-term freelance clients and had some huge successes in that time.

So no I am not an imposter. And if someone thinks you are? well we shouldn’t waste too much time worrying what other people think, unless they are your actual boss.

Do We Really Need SimpleForm?

I’ve been using simple_form for as many years as I can remember. I love it’s simplicity. We’ve been adopting DRY since we all first adopted Rails back when we were less grey. So every time you see a form input like this it pains me.

<div>
  <%= form_for(User.new) do |f| %>
    <div class="field-group">
      <%= f.label :name, class: 'form-control' %>
      <%= f.text_field :name, class: 'form-input', placeholder: 'Name' %>
    </div>
    <div class="field-group">
      <%= f.label :role_ids, class: 'form-control' %>
      <%= f.select :role_ids, options_for_select([][1, 'One'],[2, 'Two']]), class: 'form-select' %>
    </div>
  <% end %>
</div>

This example is a simple one, it doesn’t even cater for errors, placeholders, hints and even left / right alignment of inputs based on different situations.

I know we’re going to repeat this about 400 times in our application and if we want to upgrade from Bootstrap 4 to Bootstrap 5 or another CSS framework, or something custom we’re going to have to rewrite every form on the site which could take months and a developer out of circulation to do this. If you ever need an excuse not to do something. (Let’s not upgrade to Bootstrap 5 it will take a year and cost $1Billion). This is a big one.

SimpleForm offers the ability to reduce that code into one line per form group. It makes reasonable guesses about what kind of form element you want based on the data type of the Boolean is check_box, String is text, etc. However it’s customizable so you can determine on a per input basis what it should be.

<div>
  <%= form_for(User.new) do |f| %>
    <%= f.input :name, placeholder: 'Name' %>
    <%= f.select :role_ids, collection: [[1, 'One'],[2, 'Two']] %>
    <%= f.select :bio, as: :text %>
  <% end %>
</div>

SimpleForm is ridiculously customisable and it caters for so many eventualities. Your form element could have 100 variations and SimpleForm’s not so simple config file will aid you to nail your form layouts. Trouble is your simple_form config can end up looking like this. Show that to your UX/UX peeps and they will stare blankly back at you and say things like WTF, or “you’re having a laugh” or worse “NO”.

config.wrappers :select, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
    b.use :label, class: 'col-sm-7 col-md-6 col-lg-5 form-label'
    b.wrapper tag: 'div', class: 'col-sm-17 col-md-18 col-lg-19' do |ba|
      ba.use :input, class: 'form-control', error_class: 'is-invalid', data: { select: true }
      ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
    end
  end

This kind of thing works if you’re a seasoned developer, and you can remember exactly what you did last week. But if you’re anything like me I jump from thing to thing and often don’t get a chance to take stock of everything before jumping into something else. But it occurred to me this morning that it’s not SimpleForm that I’m in love with it’s the simplicity I’m in love with and the implementation I can accept is pretty cool and I like to see elaborate things but I’m not particularly in love with the way it doesn’t allow everyone in the team to understand it without a week of poking it with a stick and in the end it’s a hinderance to development.

I can offer a different solution however, Rails has offered us a way to use custom FormBuilder and has since forever. It’s very nice to have a singing dancing solution, but a simple one will suffice. A simple solution needs to have some flexibility but it only needs to cater for the needs of our team not for every Ruby outfit on the planet.

We could easily just build our own solution but for the sake of our sanity make it compatible with SimpleForm arguments so we can just swap this in by changing simple_form_for with another_form_for.

class AnotherFormBuilder < ActionView::Helpers::FormBuilder
  def input(method, options = {})
    # delegate to a single method for each kind of form input based on type or options[:as]
  end
  
  def string
  end  

  def time_picker
  end

  def toggle_switch
  end
end

def another_form_for(name, &block)
  form_for(name, builder: AnotherFormBuilder, &block)
end

Now that I’ve written this I’ve found this rather nice article after coming to this conclusion, it appears they are thinking along the same lines.
https://brandnewbox.com/notes/2021/03/form-builders-in-ruby/

Feeling slightly bad that the same week that I do a PR for SimpleForm then I’m off the mindset to move on .

SomeView.render/2 is undefined

I did a bad and ploughed into creating an update function for my form and woah begads I broke something.

UndefinedFunctionError at GET /rooms
function DungeonWeb.RoomView.render/2 is undefined (module DungeonWeb.RoomView is not available)

Now DungeonWeb.RoomView.render/2 is not there. In the backtrace it even suggests there’s nofile. There totally is…

defmodule DungeonWeb.RoomView do
  use DungeonWeb, :view
end

Not entirely sure what could cause this or cause the room_view.ex not to be loaded :S

UPDATE: 29/11/2021

It would appear that saving and changing just whitespace on my rooms/index.html.heex fixed everything. Huh? So there’s some kind of template cache that can get messed up?