“...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 InPay...”

Rob Lacey (contact@robl.me)
Senior Software Engineer, Brighton, UK

So programming languages huh?

Before I started with Ruby, I had worked with Perl, PHP, Python, and BASIC (ok, back before I was 10). Ruby has stuck and has been my goto for everything. I feel like this has left me rather stuck and lacking any kind of contrast to other solutions, problem solving, perspective on how to create effective software. So my list of things to look at over the course of the rest of my life

--
- Ruby
- Go
- Rust
- Python
- Elixir
- Erlang
- Crystal
- Haskell
- Elm
- C++ (Unreal Engine)

With any luck exposure to all of this will make my brain explode in interesting artistic patterns.

Caught my first tube this morning, Sir.

Ok, I threw this up about a week ago. Still I’ve managed to deploy my first Phoenix application to Gigalixir. It’s attempting to be a rather splendid, better than the YouTube UI for I Play Red ’s YouTube Channel …which will allow Kat the ability to publish her videos, which are then synced here but at the same time label them with the game they are for. Which allows for better searching, SEO, OpenGraph, and generally syndicating all over the shop.

Plus I have a project to build something that needs to work and we can measure success on nicely. Not like this blog where the only person that really needs to read it is me :)

Fun with classes and constants

Ruby is somewhat versatile at times. Suppose you want to define a class dynamically, and I do….

class Thing; end

Ok, that’s not dynamic

# still not dynamic but getting there.
def define_a_class
  Thing = Class.new
end

# ok then I see
def define_a_class(name)
  Object.const_set(name, Class.new)
end

define_a_class('Thing')
=> Thing

This is great but what if you wanted to define a class within a module

define_a_class('Nigel::Thing')
NameError: wrong constant name Nigel::Thing
from (pry):19:in `const_set'

Oh. That sucks. What you’re actually trying to do here is

Object.const_set('Thing', Class.new)
#=> Thing
Nigel.const_set('Thing', Class.new)
#=> Nigel::Thing

Object is for root namespace, and the module name for the nested namespace.

So today we had an issue. We normally define a Permit class if one doesn’t already exist like so.

def define_permit_class
  name = "#{self.name}Permit"
  Object.const_get(name)

rescue NameError
  Object.const_set(name, Class.new(Permit))
end

This works for

Thing.define_permit_class

But obviously not for

Nigel::Thing.define_permit_class

Well, easily fixed. A class can find it’s parent module, or if it is doesn’t have one it’s Object.

Thing.parent 
#=> Object
Nigel::Thing.parent
#=> Nigel

So we just refactor this a little and bingo

def define_permit_class
  name = "#{self.name.demodulize}Permit"
  parent.const_get(name)

rescue NameError
  parent.const_set(name, Class.new(Permit))
end

Ok, it now seems that parent is deprecated in Rails 6.1. module_parent it is.

DEPRECATION WARNING: `Module#parent` has been renamed to `module_parent`. `parent` is deprecated and will be removed in Rails 6.1.

Elixir did an explode

Just trying to boot my application after a little time away from the project. Just wondering if my my latest brew upgrade broken something here too. Node and MongoDB went foom too on the last upgrade.

Robs-MBP:i_play_red_umbrella rl$ iex -S mix
Erlang/OTP 25 [erts-13.0.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns] [dtrace]


11:17:06.689 [error] beam/beam_load.c(86): Error loading module 'Elixir.Code.Formatter':
  lambda already defined for label 744. To fix this, please recompile this module with an OTP 25 compiler.


 
11:17:06.689 [error] Loading of /Users/rl/.asdf/installs/elixir/1.13.1/bin/../lib/elixir/ebin/Elixir.Code.Formatter.beam failed: :badfile

** (UndefinedFunctionError) function Code.Formatter.locals_without_parens/0 is undefined (module Code.Formatter is not available)
    (elixir 1.13.1) Code.Formatter.locals_without_parens()
    (elixir 1.13.1) lib/code/normalizer.ex:22: Code.Normalizer.normalize/2
    (elixir 1.13.1) lib/code.ex:1107: Code.quoted_to_algebra/2
    (elixir 1.13.1) lib/macro.ex:948: Macro.to_string/1

Ok so it’s using OTP 25 but it’s compiled with OTP 22?

Robs-MBP:i_play_red_umbrella rl$ elixir -v
Erlang/OTP 25 [erts-13.0.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns] [dtrace]

Elixir 1.13.1 (compiled with Erlang/OTP 22)

Uninstalled and Re-Installed via asdf and it seems fine now.

Robs-MBP:i_play_red_umbrella rl$ asdf list elixir
  1.12.1
  1.13.1
Robs-MBP:i_play_red_umbrella rl$ asdf uninstall elixir
Robs-MBP:i_play_red_umbrella rl$ asdf list elixir
  No versions installed
Robs-MBP:i_play_red_umbrella rl$ asdf install elixir 1.13.1
==> Checking whether specified Elixir release exists...
==> Downloading 1.13.1 to /Users/rl/.asdf/downloads/elixir/1.13.1/elixir-precompiled-1.13.1.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 6068k  100 6068k    0     0  9689k      0 --:--:-- --:--:-- --:--:-- 9772k
==> Copying release into place
Robs-MBP:i_play_red_umbrella rl$ asdf list elixir
  1.13.1
Robs-MBP:i_play_red_umbrella rl$ elixir -v
Erlang/OTP 25 [erts-13.0.3] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns] [dtrace]

Elixir 1.13.1 (compiled with Erlang/OTP 23)

What version of Erlang do I have installed anyway?

Thought erl -v might do the trick but that’s only the major version.

erl -eval '{ok, Version} = file:read_file(filename:join([code:root_dir(), "releases", erlang:system_info(otp_release), "OTP_VERSION"])), io:fwrite(Version), halt().' -noshell

OK, 25.0.2 then.

Robs-MBP:i_play_red_umbrella rl$ erl -eval '{ok, Version} = file:read_file(filename:join([code:root_dir(), "releases", erlang:system_info(otp_release), "OTP_VERSION"])), io:fwrite(Version), halt().' -noshell
25.0.2

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.