more info ⬇

@amattn

SW engineering, engineering management and the business of software

subscribe for more
stuff like this:

2021 01 01

2020 Year in Review

This is a set of bullet point lists about variously things I’ve done, experienced or come across in 2020. Items listed in no particular order.

Inspired by Fogus.

Past editions: 2019 Year in Review

Jobs:

Advisory:

Programming Languages & Technologies

I like very much all of the above technologies. Elixir in particular, I’m very happy with. It is relatively new to me though, so I may be in a honeymoon phase.

Content:

Popular Content by me:

My most popular content of 2020 According to Analytics:

Some of those are ancient. There are 2011, 2012 and 2013 era technical tutorials still getting SEO hits for some reason.

Apparently, my engineering management or recruiting content doesn’t rate.

Content I’m proud of:

It doesn’t get any SEO juice, but I’m proud of the management content I write.

Also I’m quite proud of what I stream at https://twitch.tv/amattn It’s mostly Elixir content these days, but hoping to do more around engineering management and recruiting.

Health:

Learning:

Roughly a 5% increase. This isn’t really indicative of learning however as I’ve been using the Notes.app built-in to MacOS and iOS far more lately. as of today, 907 note entries. around 300 of them were created or edited in 2020.

Best Blog posts or other content read

The best stuff I come across I will typically post on twitter.

Best Books Read

Overall number of books read in 2020: ??? across paper, kindle, iBooks.

Favorite Media:

Disney+ is killing it with content suited to my tastes. The family prefers Netflix, but I’ll likely be a D+ subscriber for a long time.

Favorite Gadget:

One of those little round robo-vacuums.

Favorite Life Tip:

Inspired by this reddit thread, I think this could be a great question to ask to learn something quickly:

What feature of X is used very often by experienced programmers/users/etc, but not so much by a newbie?

Travel

Obviously, not a big year for travel.

Conferences

Obviously, not a big year for conferences.

Recap: Todo in 2020

The 2020 Todos were originally published in my 2019 Year in Review

Did not accomplish:

Todo in 2021

2021 01 12

Deploying Elixir Phoenix webapps to the cloud with releases

I love many things about go. One of my favorite things is that cross-compilation is an absolute breeze. It takes just seconds and it’s especially easy with a tool like gox. After that, deployment is even easier. Just rsync or scp your executable binary and maybe a secret file or two. Boom💥 done. It’s essentially the easiest possible deployment story of any langauge or framework I know of.

So as a long time go developer (nearly a decade!) every other ecosystem pales in comparison.

Elixir is among them. Elixir itself is nearly a decade old, so there has been a lot of community work to make this better over time. As someone relatively new to this lovely language, I’m super grateful for all the hard work. Deploying basic Phoenix apps isn’t golang-easy, but’s it’s not painful.

This post details how I deploy a phoenix webapp, developed on a Mac to a single linux cloud instance.

Tooling

First off, as you read about deploying elixir apps, you’ll see two primary release tools.

The first is an older tool that predates mix release. As I understand it, Distillery was essentially a community tool created to help with production deployments. mix release is realtively new, and is bundled with Elixir 1.9. Most of the new development and tooling is built around mix release. At least one long time Elixir dev I talked with seemed to think that mix release is the future.

I didn’t spend much time with Distillery, but mix release is a nice little tool. It essentially is able to package everything you need to run an Elixir app into a single directory. the layout looks like this:

/my_app-1.2.3
    /bin
        my_app
    /erts-1.11.5
        /bin
    /lib
    /releases
        /1.2.3

The /my_app-1.2.3/bin/my_app is a simple shell script that you can use to start, stop, check version, launch in daemon mode, or even eval or call rpc expressions. /erts-x.y.z is the erlang VM. /lib is your app and all it’s dependencies. releases is a bunch of misc helper files, scripts, etc.

These release directories are essentially self-contained and can simply be scp’d or rsync’d to a remote cloud instance. rsync is preferred as most of it doesn’t change between releases. I typically see 100x or more speedups using rsync.

For this post, I added the following definitions to mix.exsproject definition:

def project do
  [
    app: :my_app_,
    version: "0.3.2-a.2",

    <snip>

    default_release: :my_app,
    releases: [
      my_app: [
        include_executables_for: [:unix],
        include_erts: true,
        strip_beams: true,
        quiet: false,
        steps: [:assemble, :tar]
      ]
    ]
  ]
end

Read the Documentation!

Assuming you are deploying a webapp, you will definitely want to start with the Phoenix release documentation:

https://hexdocs.pm/phoenix/releases.html

You are going to want to exit any files the above link tells you to edit. In particular, the stuff about prod.secret.exs and release.ex. The actuall steps are automated with scripts I’m detailing below.

For release.ex I had to add a line to make it work. Specifically, I needed to start :ssl in the load_app function:

defp load_app do
    Application.load(@app)
    Application.ensure_all_started(:ssl)
end

Additionally, the mix release hexdoc page has more details that help explain what is going on under the hood:

https://hexdocs.pm/mix/Mix.Tasks.Release.html

Definitely read the first, and I recommend reading both.

Building:

With Elixir, cross-compiling is theoretically possible, but it’s not tested and not supported in any way.

Update: I’ve since learned that cross-compilation may not be as dangerous as I first assumed. See here: https://github.com/LostKobrakai/criss_cross

For the common case of building on a Mac or Windows machine and deploying to a linux cloud instance, you need a way to build on linux. Your basic strategies come down to:

For this post, I’ll walk thru the first.

For the second, just do a git checkout or rsync your project to the cloud instance and mix compile && mix release. You’ll have to make sure that elixir and any dependencies you need are installed on the cloud instance.

For the third, see the Phoenix documentation here.

With CI tools, reference your CI tool of choice to see if existing documentation exists or try to implement one of the above strategies via the CI tool.

Build in docker, spit out a tarball

First credit and thanks to Kai Wern Choong and their post about deploying Phoenix. It was super helpful to as I was learning about how to deploy with docker.

Here is the script I use to build a Phoenix app inside of a linux docker container, then spit out a tarball:

#!/bin/sh

set -o nounset
set -o errexit

#######
# build project in a dockerfile then output a tarball to sync with external server
# primarily using this post as a resource: 
# https://kaiwern.com/posts/2020/06/20/building-elixir/phoenix-release-with-docker/#build-image

export DATABASE_URL=`cat postgres.secret`
export SECRET_KEY_BASE=`mix phx.gen.secret`

docker build --build-arg DATABASE_URL --build-arg SECRET_KEY_BASE -t my_app_server .

APP_NAME="$(grep 'app:' mix.exs | sed -e 's/\[//g' -e 's/ //g' -e 's/app://' -e 's/[:,]//g')"
APP_VSN="$(grep 'version:' mix.exs | cut -d '"' -f2)"
BASE_NAME=${APP_NAME}-${APP_VSN}
TAR_FILENAME=${BASE_NAME}.tar.gz

id=$(docker create ${APP_NAME}_server)
docker cp $id:/app/${TAR_FILENAME} .
docker rm $id

mkdir -p _staging/${BASE_NAME}
mv ${TAR_FILENAME} _staging/${BASE_NAME}/.
cd _staging/${BASE_NAME}
tar -xf ${TAR_FILENAME}
rm ${TAR_FILENAME}

It will simply create a directory called _release and put any release it builds in there.

The SECRET_KEY_BASE env variable is used for things like session tokens. In this script we regenerate everytime, but that will essentially log out all your users every release. SECRET_KEY_BASE should be persisted accross releases if you don’t want that behavior.

Here’s the Dockerfile I use: https://gist.github.com/amattn/037e3ef59c02140efe60b8aa1c00b687

Walking thru the Dockerfile we are essentially doing the following:

Deploying

Next I have a simple deploy.sh script that deploys a version to an environment (dev|test|staging|prod). It’s not the most elegant script. But it’s my script and I love it:

https://gist.github.com/amattn/ce12a89ceebe402e464ef3c43147f930

This script does assume you have ssh keys or whatever setup.

Here’s what is going on in there:

Lastly, a fairly typical systemd service file (that is rsync’d by the deploy.sh script):

[Unit]
Description=myapp
After=network.target

[Service]
ExecStart=/home/USERNAME/my_app/bin/my_app start
ExecStop=/home/USERNAME/my_app/bin/my_app stop
ExecReload=/home/USERNAME/my_app/bin/my_app restart
WorkingDirectory=/home/USERNAME/my_app
StandardOutput=inherit
StandardError=inherit
Restart=always
User=USERNAME

[Install]
WantedBy=multi-user.target

SSL

I use caddy in front of the Phoenix app to get https working.

A v2 Caddyfile directive will look like this:

# myapp.com reverse proxy
myapp.com {
    reverse_proxy localhost:4000
    encode zstd gzip
}

Caddy is the easiest way to get a Let’s Encrypt cert. It happens automatically. It’s basically a miracle compared to the hoops we used to jump thru before Let’s Encrypt was a thing.

All done

My time to automate deployment for my first Phoenix app was about a day and half.

The final steps would look like this:

A good chunk of it was just understanding what was going and debugging the Dockerfile (esp those ENV variables). My Docker-fu is a bit rusty these days.

Conceptually, nothing really hard is going on here. Using the above scripts and files as a template, that time to deploy should be much much shorter.

All the hard work was done by the Elixir community members who worked on the mix release functionality. Their work makes it so that I can deploy to a cloud instance without having to worry about what version of what package is installed on that cloud instance. I’m too spoiled to go back to the days where your release artifact has system dependencies. That way lies madness.

All in all, Elixir’s deployment story, like Elixir itself, has a bit of a learning curve, but ends up rather pleasant after you figure it out.

2021 01 14

The Sublime Developer Efficiency of Elixir, Phoenix and LiveView, Part 1

Editor’s note: This is part one of a short series. You can find part two here.

I’ve spent the last month and change working on a little side project.

The interesting thing about this one is that it’s written completely in Elixir. This is a post about my experience doing so.

Elixir is a language that came out of the heyday of Ruby on Rails about a decade ago. It was originally billed as “Ruby on the Erlang VM”, trying to blend the best of both worlds. Spoiler, I believe it has largely succeeded.

It’s still got quite a bit of Ruby influence, but overall, it’s much more functional. You will see maps, filters and reduce’s all over your code base.

From the Erlang side of the family, you’ll see a lot. There’s no mutability. Variables cannot be changed, you can only create new ones from combining or transforming existing. Pattern Matching is everywhere and it’s still quite powerful. You can trivially call down to Erlang primitives whenever you need to.

The Ruby influence is more in style and syntactic sugar. You’ll see your def’s and end’s and ->’s. You can skip parenthesis around function arguments if it doesn’t introduce ambiguity. There’s no early return, you always return the last expression. Map and list syntax will be fairly familiar. The @ prefix denotes attributes / decorators. Atons.

It’s got some quirks. The native list primitive is a classic linked list, not an array. This means that prepend is cheap, but count, insert, append is expensive. It also means you can do head/tail car/cdr operations quite easily. Keyword lists as a weird list/map hybrid.

Digging into the pipe operator

The |> operation is a particularly good example. To most newcomers, it’s a weird, inscrutable symbol whose operation isn’t easily intuited.1 Yet once you get used to it, there’s quite a bit of elegance to it, and even historical reference to the pipe operation in the shell.

For those new to the language it works like this: take the input of the pipe operation (x below) and pass it as the first argument of the target function of the pipe operator.

x
|> function(y, z)

is equivalent to

function(x, y, z)

The elegance comes from chaining these together like so;

x
|> function(y, z)
|> other_function(a, b)
|> yet_another_function(c)

If this is the last expression in a function you return the results of the final yet_another_function

You can also bind it to a variable like so:

final_output =
  x
  |> function(y, z)
  |> other_function(a, b)
  |> yet_another_function(c)

The pipe metaphor breaks down as you start with x, do a ton of transformation on it and your eyes have to scan way back to the beginning to see what variable you are assigning the final results to.

It kind of micro-example of the entire macro-experience of using Elixir:

An actual example

To see an actual code snippet with pipes in action:

collected_errors =
  Date.range(start_date, yesterday)
  |> Enum.to_list()
  |> Enum.filter(fn _ ->
    random_number = :rand.uniform(100)
    random_number < 75
  end)
  |> Enum.map(fn date ->
    make_map_of_attrs(date, user, some_bool, some_int)
  end)
  |> Enum.reduce([], fn entity_attr, all_errors ->
    case create_entity_with_attr(entity_attr) do
       {:ok, _entity} ->
         all_errors
       {:error, err_msg} ->
         [err_msg | all_errors]
    end
  end)

If the above looks like moon runes, it’s probably just because the syntax is new to your eyes. After a week or so with the language, it reads very clearly. Walking thru that snippet, we start with the second line:

  1. Create a date range between two dates (a range is essentially an entity with a start and end.)
  2. Take that range and convert it into a linked list, filling in all the dates inbetween
  3. Throw away about 25% of the dates, randomly
  4. For each date, create a struct (map) which contains kv pairs of data, including the date.
  5. Take that list of maps and create defined structs. Typically a create_ prefix means you are creating and object and often storing it in some persistence layer.
  6. Finally we put the result of the reduce operation (any accumulated errors) and bind that to the collected_errors variable.

The endgame is high developer efficiency

I’m very, very fond of go, but a typical implementation of equivalent functionality would typically be at least 5x longer and certainly more irritating to write.

So, back to that macro experience of using Elixir:

That last bullet point, in my relatively short experience with Elixir, I’m fairly certain the overall developer productivity is quite high. Likely in the top quartile or better of all development environments (possibly even top 10%). There are others who think so as well.

The combination of the last two bullets is what I refer to as sublime efficiency in the title of this post. This is a rare combination. I believe go to be a great language for “IDE to prod” developer productivity, but I don’t believe it is a particularly elegant language. Lisp and it’s variants can be quite elegant but you will run into feature velocity problems at some point (deployment, ecosystem, hiring…).

Developing in a modern functional language, with great safeguards (pattern matching, guards, type annotations, strong testing libraries, etc.) somehow allows developers to be efficient, write elegant code and also achieve high feature velocity.

It’s clearly not a perfect language or ecosystem. The deployment story is not as good as go.2

But it is one that I could see a lot of companies using as a competitive advantage with respect to time to market of getting product out.

All you have to do is get over the learning curve.


Authors’s Note:

This post is the first of a two part series. You can find the second part here.

Lastly, I do live code streaming about Elixir, Phoenix, and LiveView on twitch.tv. You should follow me there.


Footnotes:

  1. OCaml and F# have a similar operator and predate Elixir. The creator of Elixir himself thinks it came from F#.
  2. To be fair, no language ecosystem has a deployment story as good as go. I would put elixir above any other dynamic language like python, ruby. Being dependent on the erlang VM, it’s more like deploying a Java app (if you squint). The tooling is there and actively getting better.
2021 01 14

The Business Case For LiveView Is Strong Enough To Change How You Staff Your Dev Team

This is part two of a short series titled “The Sublime Developer Efficiency of Elixir, Phoenix and LiveView”. You can find part one here.

To recap the initial thoughts on Elixir:

The above is a succinct summary of my experience using Elixir. My overall impressions of the language, tooling and broader ecosystem are quite positive.

Phoenix

The Phoenix web framework is (as far as I can tell) the crown jewel of the aforementioned broader Elixir ecosytem.

It’s an opinionated web framework, with a bit of magic and convention in it. Just like Elixir was strongly influenced by Ruby, Phoenix’s ancestral roots point to Ruby on Rails.

It’s a great framework. Like Elixir itself, it is quirky & has a learning curve & elegant & you can be quite productive with it. If you are coming from an environment where everything is explicit, the magic and convention steepens the learning curve a bit, but that’s part of the productivity tradeoff.

It is based on the classic MVC paradigm. Elixir’s template language, Eex, essentially compiles down elixir code. It’s fast enough. You can scale vertically, horizontally with a load balancer or with any fancy cluster management solution. The Ecto ORM and Postgres integration quite well done. Ecto itself is, you guessed it quirky, learning curve, etc.

The thing about Phoenix however, is that it’s just an opinionated MVC web framework. Plain old Phoenix isn’t enough for me to radically adjust how I think about creating new web apps or change how I staff up engineering teams.

Ruby on Rails was a tremendous productivity booster during a good chunk of it’s early life. You could make reasonable and often convincing business cases for developing Rails. However, it is 2021; many other web app ecosystems have caught up or surpassed its vermillion tracks.

Phoenix LiveView

LiveView is a relatively new extension to Phoenix. The first release, 0.1.0, was published in August of 2019 and I believe work started in 2018.

Spoiler: LiveView is more than enough for me to consider transitioning a large amount of work to the Elixir/Phoenix platform.

The way it works is tremendously clever. There’s some liveview javascript you include in your html. Then you defined your live view templates like you always do, but with a special .leex suffix (LiveView Eex).

Your typical template will look like this

<html>
    <head>
        <meta charset="utf-8"/>
        <%= live_title_tag assigns[:page_title]%>
    <head>
    <body>
        <h1>
            User Details
        </h1>
        <ul>
            <li>
                username:<%= @user.name %>
            </li>
            <li>
                email:<%= @user.email %>
            </li>
        </ul>
    </body>
</html>

What Liveview does (conceptually) is takes all those embedded elixir tags, and creates a map like so:

{
    0: "User Details Page",
    1: "Jane Doe",
    2: "jane.doe@example.com"
}

When the page is sent to the browser for the first time, those elixir tags are filled in server side. you will see the right values even if javascript is turned off.

The magic happens next. LiveView sets up a websocket to the server. The client can send events like phx-click="checkbox_toggle", phx-capture-click="close", phx_change: "validate", phx_submit: "save", etc.

The server can then do any backend processing, such as change a users email, save it to a database and email a notification. Maybe calculate a new estimate of shipping time for updated contents of a shopping cart. Anything a server needs to do really.

Then, instead of a 302 redirect to reload the entire page to refresh the content (email, cart, whatever), LiveView will send just the data over the websocket like so:

{
    0: "User Details Page",
    1: "Jane Doe",
    2: "janes_work_email@example.com"
}

There’s a bit of javascript logic that rerenders just that part of the DOM with new values. in this case, the <li> with the updated email.

What you get is the speed, responsiveness and UX performance exceeding that of a React/Vue/javascript front end framework against a server API, but you haven’t written a line of javascript.

This is a magical feeling.

Another similar-in-spirit technology is Hotwire. Hotwire however, sends little bits of HTML over the socket instead of tiny chunks of data, but conceptually, they are quite similar.

A lot of productivity gains of the Elixir/Phoenix/LiveView stack1 is based on the fact that you can build modern browser experiences without having to write any javascript whatsover.

Phoenix does have a webpack dependency, but it comes preconfigured and the javascript glue code that makes LiveView work is all written for you and included with the framework.

LiveView’s primary advantages:

Hours per feature

I can’t stress how important the first point above is. The way to faster development cadence is rarely “add more developers”. Usually, it’s make them write less code to do good work.

CI/CD makes developers faster, because more of the testing and deployment is automated, drastically reducing human error, reducing code review time, human time on keyboard per deploy, and importantly reducing risk.

Good Project Management improves feature velocity because developers are typically better coordinated with design, product, marketing, etc. They end up writing the more important bits first.

Good Customer Development or User research improves developer productivity because they build features that people use instead of stuff that doesn’t move the needle on business goals.

LiveView makes it so you don’t have to write javascript.2 A poor metaphor: This is a like saying a car repair shop doesn’t need to paint or do body work anymore. All there customers are totally satisfied with having a running enginer.

Obviously, you still have to do HTML and CSS. LiveView is amazing, but it’s not a miracle. All logic is written in elixir and executed on the server. There is no javascript logic required whatsoever.

If you do need some fancy Javascript functionality, there are hooks built-in to the framework that allow arbitrary javascript to send events to LiveView and vice versa.

Sublime Developer Efficiency

LiveView, like the rest of the broader ecosystem, continued the streak: Quirky, Learning Curve, Elegant, High Feature Velocity.

Again, Elixir and Phoenix are quite good, but the productivity gains of LiveView are great enough for me to strongly favor it for all new projects and seriously consider rewriting certain existing projects in that stack. The business case for using LiveView is that strong. It changes the total headcount and makeup engineers I need for a given web app team.3

So that title up at the top? that part-cheesy, part-aggrandizing line about Sublime Developer Efficiency? That’s LiveView. After you get past the quirks and the curve, it’s pleasant to work with and there’s a strong business case to be made that you or your team are going to be really productive with it.


Authors’s Note:

This post is the second of a two part series. You can find the first part here.

Lastly, I do live code streaming about Elixir, Phoenix, and LiveView on twitch.tv. You should follow me there.


Footnotes:

  1. This stack now has an acronym: PETAL coined by Patrick Thompson. Phoenix, Elixir, Tailwind, Alpine, Liveview. If you are not familiar with it, TailwindCSS is also amazing.
  2. It’s not my intention to dump on javascript, but there are real pains in that ecosystem: giant node_modules, dependency hell (leftpad), reliance on node and npm with almost no alternatives, etc.
  3. You probably need somewhere between a fifth to a third of your current front end team. Maybe even less because the HTML you generate will be significantly simpler in terms of complexity. Convert them to full stack, or just run a leaner eng team. I’m hearing that good Ruby/js developers can get productive in about 2 weeks and competent in about 3 months. After that, retention is high.


the fine print:
aboutarchivetwittertwitchconsulting or speaking inquiries
© matt nunogawa 2010 - 2021 / all rights reserved
back ⬆