upinetree's memo

Web系技術の話題や日常について。

Ergo42 Towel を作った

遊舎工房さんの実店舗でキットを購入。meishiを除けば最初の自作キーボードだったので、作りやすそうで、コンパクトだけどある程度キー数があるスプリットキーボードという点で選定。

構成

  • キースイッチ
    • Gateron Silent Brown * 56
  • キーキャップ
    • MDA Big Bang セット

ログ

f:id:upinetree:20190505103522j:plain

ダイオードのはんだ付けが完了したところ。付属のアクリル脚の幅が曲げるのにちょうどよかったので、簡易的なリードベンダーとして利用してみた…が、雑に行ったせいで仕上がりはそんなにきれいではない。

f:id:upinetree:20190506121821j:plain

キースイッチのはんだ付けが終わったところ。ケースの組み立て前にそれぞれのスイッチをテスタで導通確認し、ファームウェア書き込んで動作確認。

f:id:upinetree:20190506235112j:plain

ケースを取り付けてキーキャップを乗せたところ。これで完成!

と思いきや、ここからが長かった。

キーマップ

せっかくなので親指を酷使できる配列にしたいとか、キー数が少ない中で効率的な記号配置をしたいとか、でも慣れるのに時間のかかる配置は避けたいとか、キーマップにはいろいろと悩んだ。

ファームウェアを書き込んで実際に触ってみると、普段のユースケースではつらい場合があることもわかったり、なるほどこれがキーマップ沼かと実感。慣らしつつ少しずつ育てていくのがまたひとつの楽しみなのだろう。

とりあえず今のところは以下の配置にしてみている(すでに上記の写真とは違う)。

f:id:upinetree:20190512221730p:plain

感想

  • 親指を酷使する配列は指の移動が減って小指が快適
  • 慣れるまでが大変そう。格子配列もまだTypoしまくるし、すべてのキーが同じ大きさなので指先の感覚が今までと違う
  • MDAキーキャップだと高さ(とくに最下段)が合わなくてガタガタになる。DSAとかを買い増しかしら…
  • Pro Micro の microUSB 端子がもげやすいと聞いて用意したZrseのマグネット式ケーブルが便利だった。端子部分を余分に用意しておくとファームウェア書き換えのときに差し替えがらくちん
  • 持ち運び用のいい感じの入れ物がほしい

meishi キットで自作キーボードに入門した

自作キーボードが作りたくて遊舎工房さんに行った。 yushakobo.jp

Ergo42 Towelmeishi キット を購入。 買うときにいろいろと教えてくれたり、こちらのふわっとした相談に乗ってくれたりしてありがたかった 🙏

meishi キットは練習用に買ってみた。 ハンダ付けとか10年くらいやってないし、いきなり作り始めるのも危険そうだったので…。

小さなキットでもキーボードに必要な最低限の要素が詰め込まれていて、入門用として最適だった。 案の定つまづくこともあって、作っといてよかったなーと思った。

f:id:upinetree:20190413233859j:plain
完成したmeishi

キースイッチは、左から

色々試せて楽しい。

Pro Micro の MicroUSB 端子はもげやすいという噂を聞いたので、マグネット式のケーブルも買った。

キーマッピングは今のところ何が便利か思い浮かばず、とりあえず Slate で割り当てていたウィンドウ切り替えに対応させてみた。

便利…か?

https://docs.qmk.fm/#/keycodes あたりを見て、 qmk_firmwarekeyboards/meishi/keymaps/default/keymap.c を変更してファームウェアをビルド&書き込み。 お手軽。

さあ次は Ergo 42 Towel を作っていくぞー。

Rails Developer Meetup 2019 に参加してCSSの技術的負債について発表した

発表内容

https://railsdm.github.io/#session-upinetree

CSSの技術的負債との向き合い方」というタイトルで、普段のチーム開発で目をつぶりがちなCSSをテーマに話しました。

プログラマからの視点で、どういう流れでCSSが負債になるのか、その負債に対してどう取り組んで行けるか、などを色々考察してみたという内容です。

質疑応答: https://railsdm.herokuapp.com/issues/118

スライド

日本語版

英語版

動画

(怖くてまだ自分自身で見られていません…)

感想

以下、感想を思いつくままに並べてみます。

全体

  • とても楽しくて濃い2日間だった
  • この規模のイベントを運営されたカルパスさんすごい
  • 動いているDHH氏を見られてよかった。準備もなしに、饒舌に自分の意見をスラスラ言っていたのが印象的だった
  • 発表が終わった後は他のセッションに気が向くまま参加。疲れていたのもあって休憩していた時間も多かった
  • 2日間共おいしいコーヒーが提供されてとてもQOL高かった
  • これからアップされた資料や動画をゆっくり見て行きたい。RubyKaigiもあるのでそれまでには…

登壇

  • ランチでの現場Rails本のトークセッションから続けての登壇。1時間以上スクリーンの前にいることになってしまったので、結構気疲れした。発表終わってからしばらく放心してた
  • B会場は110人入るとのことだったけど、だいたい席が埋まっている感じで、まさかこんなに多くの人の前で話すことになるとはという感じ

良かったところ

  • 緊張はしていたが、話し始めてからはリラックスしていられたと思う
  • ペースを意識しながらやれた
    • スライドの途中にここまで何分でできたら急ぐ、みたいな目安を決めていた。30分ぴったりで終わって我ながらよくやった
  • 良かったという感想が多くてホッとした
    • CSSは専門領域じゃないので、何適当なこと言ってんだみたいな反応ないか怖かった
    • 関心の谷っていうメタファーいいよねといろんな方に言われてうれしい
  • 全体の構成を紙に書いて考えた
    • 30分ともなると箇条書きで考えるのつらそうだったので
    • マインドマップ的なやつとか、色々絵を書いた
  • 英訳をがんばった
    • 必須ではないし、会場に英語話者の方がいらっしゃっていたかは不明だけど、チャレンジしてみた
    • 海外でのチーム開発や職責の事情は違うのかもしれないけど、リーチできるってのは良いことだ

改善できそうなところ

  • 詰め込みこみすぎた
    • ペースを早めにしないと時間が足りなくなってしまった
    • 息継ぎが少なめになってしまって結構苦しかった
  • ブラッシュアップ期間が取れなかった
    • もう少し余裕を持てたら良かった
    • ブラッシュアップしたらシンプルにできて発表時間に余裕を持てたかもしれない
    • 負債自体は悪くないんだよという話も入れたかったなー
  • スライドが文章だらけになってしまった
    • 何を話すか思い出すためでもあって、これもブラッシュアップできなかった影響
  • 英訳にかかる時間を甘く見ていた
    • 結果として途中まで英語という中途半端な形で発表することに…

今後やってみたいこと

  • Stylelint で橋の使われ方のチェック
    • 発表では「橋が巨大になるに連れて使われ方のチェックが大変になる」という話をしたが、そのあたりも自動化できたら良さそう
  • 谷を埋める方法の掘り下げ
    • みんなでがんばっていくぞ的な抽象的な内容で終わってしまった
    • じゃあその分のコストはどうするのとか、やりたくない、やらないほうが価値を発揮できる人にもやらせるのかとか、色々議論したい
  • 他の領域での関心の谷
    • CSSに限らずあると思うので、色々ディスカッションしたい
    • まずは認識することが大事で、そこからチームで踏み出せていけたらなと思う

自分の結婚式用にサーバレスな招待状Webアプリを作った

結婚しました

2018/12/1 (土) に結婚式を行いました。天候に恵まれ、穏やかな晴れの日で式を挙げられて本当に良かったです。私のことなので直前で体調を崩すか怪我をするか天気が崩れるかのどれかはあるんじゃないかと思っていたのですが、何もなく無事に終えることができて安心しました。

我々夫婦のために多くの方々が集まってくれてとても嬉しかったです。遠くからはるばる来てくださった方もいて、本当にありがたい限りです。

よちよち.rb からも電報をいただいてしまってびっくりしました。 curl から始まり | ruby で終わる電報をいただく(そして困惑する司会の方がゲストに促されそれを読み上げる)機会はそうそうないでしょう 😂 お忙しい中、粋な計らいをありがとうございました。

披露宴の内容やアイテムにはかなりこだわって、我々らしいオリジナリティのある結婚式になったと思います。夫婦で演奏したりもしました(私がギター、妻が鍵盤ハーモニカ、ヴィブラフォンマリンバ)し、謝辞にLTしたりもしました。

現場Rails本の執筆と並行しての準備となってしまってかなりきつかったけど、妻に主導してもらってなんとかなりました。本当に感謝。そしてようやく締切に追われない日々が訪れ、ブログを書くこともできるようになりました。

これから夫婦ともどもよろしくお願いいたします。

(というわけで例のリストです)

http://amzn.asia/0Ly1XAG

招待状Webアプリ

結婚式のこだわりのひとつとして、招待状の回答をWebアプリでできるようにしてみました。せっかくなのでその紹介を書いてみようと思います。

なぜ招待状の回答をWebアプリでできるようにしたかというと、従来のはがきでの回答には以下の扱いづらさがあったからです。

  • 「御」を打ち消したりといったマナーがたくさん。ゲストに手間をかけさせたくない
  • 当日の情報を見たいときにすぐ見られない。地図の検索などの一手間が必要
  • 返信用切手の購入や添付が必要
  • 回答の集計が手入力で大変

一方で、はがきには紙の良さもあります。色々とデコったり、文字でメッセージを伝えたいといった需要もありますし、モノとして手元に残るのはうれしい点です。

そこで、今回は以下のような運用にしてみました。

  1. 招待状は紙で送付。ゲストカードと、招待状アプリの案内カードを同封
  2. 招待状アプリの案内カードには、アクセスするためのQRコードと、ログインパスコードを記載
  3. 招待状アプリで回答していただく
  4. こちらが集計スクリプトで回答結果をチェック(毎日のたのしみ)

QRコードの用意やログインパスコードの添付など、物理との接続のための工夫はかなり苦労しました。正直この作業中ははがきのほうが数倍楽だったのではとも思いましたが、苦労した分だけ楽しみつつも総合的に満足できるものができたかなと思っています。

アプリケーションの構成

公開用に個人情報とか抜いたリポジトリを作ってみました。

https://github.com/upinetree/wedat-demo

今回は前々から興味があったサーバーレスSPAでやってみました。AWSを中心に以下のような構成にしました。

  • リソースは S3
  • 回答結果を DynamoDB に保存
  • API Gateway で DynamoDB にアクセス
  • 認証は Cognito
  • ネットワーク周り
    • CloudFront
    • Lambda@Edge (テスト環境のBasic認証用)
    • Route 53
    • Amazon Certificate Manager

なお、これらの構成は Terraform で管理しました(勢いでかなり雑に…)。

今回はSPAということで、フロント周りはReactで組みました。CRAでシュッと作って、その上に以下の色々を乗せた感じです。

  • Redux
  • Redux Form
  • React Router
  • React Transition Group
  • Luxon
  • Styled Components
  • Tailwind CSS
  • AWS Ampify

なお、CRAの Service worker は途中まで使ったり整備したりしたのですが、キャッシュの更新とかの懸念点の解消が公開に間に合わず、泣く泣く外しました…。

作ってからCRAもAmplifyもかなり大きなアップデートが入っていて、追従できていないのも心残りではあります。作って利用してもらうことが最優先だったので、目的は達成できたということで良しとしています。

やってみた感想

Webアプリにしてみて感じたのは

  • 紙面のような限界がないので、長文でコメントくれる人も結構いてうれしかった
  • 結構びっくりしてもらえた。製品かと思わせることに成功
  • 集計がめっちゃ楽。毎日集計結果とメッセージを確認できるのでモチベーションになる
  • ゲストに名前を入力してもらうので、名前の正確な漢字に手書きよりも確実に気付ける

のあたり。やってよかったな〜と思いました。

技術的な感想としては

  • サーバレスSPAめっちゃ低コストで月に多くて100円程度しかかからない。運用もほとんど気にしなくていい(一応トラッキングはしていたが、安定してからは本当に手が離せて助かった)
  • CRAやAmplifyのレールからはずれたいときに大変だった。結局ソースコードを読みに行った
  • Amplifyが提供するReactコンポーネントはカスタマイズがあまりできなくて、上書きしたりしたり、同じような機能を持つコンポーネントを自作したりした
  • Styled Components 最高だ。Tailwind CSS でざっくりマークアップして、まとまりがでてきたらコンポーネント化するというパターンがかっちりきた
  • API Gateway でとても苦労した。Terraformでの管理が一つ一つのリソースに対して記述量が多くて大変だった。マッピングテンプレートのVTL (Velocity Template Luangage) の記述方法でもめっちゃハマる。これでサーバーレスで柔軟なエンドポイントを定義できると考えて、トレードオフとしてはありのようななしのような…?代替手段があればまずそっちを選択すると思う
  • Cognito もちょっとレールからはずれた使い方をするととたんに応用が効かなくて苦労した。次は Auth0 とか Firebase auth とかも使ってみたい
  • (最終的には採用しなかったけど)Service worker は、キャッシュの扱いで苦労した。キャッシュはCDNにあるのかSWにあるのかブラウザにあるのか、どこの設定が効いているのか、というところ。この規模のアプリのSWキャッシュでそんなに苦労に見合うメリットはないと判断した
  • それぞれのサービスやフレームワークを組み合わせたベストプラクティスがなくて、その都度自分で判断しないといけなかったのは大変だったけど楽しかった。普段書いてるRailsは(レールに乗っていれば)だいぶ楽できるなと再確認

技術的な方はその都度アウトプットできたら良かったのですが、執筆という巨大なアウトプットの最中で断念しました。まだ使える知識がありそうだったらこれから出してみようかと思います。

Minitest の Unit style で DSL 風な around ヘルパーを定義する

RailsActiveSupport::TestCase を使っているとして、サクッとミニマムにやりたい。

minitest-around を使うと、以下のような around メソッドを定義することで setup/teardown をセットで実行できる。

require "test_helper"
require 'minitest/around/unit'

class CatTest < ActiveSupport::TestCase
  def around(&block)
    p "konnichi nyan"
    block.call
    p "sayouna nyan"
  end

  def test_nyan
    # ...
  end
end

でも、なんとなく ActiveSupport::TestCase が用意している setup, teardown と揃えてDSL風に使いたい。

require "test_helper"
require 'minitest/around/unit'

class CatTest < ActiveSupport::TestCase
  # こうしたい!
  around do |test|
    p "konnichi nyan"
    test.call
    p "sayouna nyan"
  end

  # これと同じ感じ
  setup do
    @cat = Cat.new
  end
end

なので test_helper.rb でこうする。

class ActiveSupport::TestCase
  def self.around(&block)
    define_method(:around) do |&test|
      instance_exec(test, &block)
    end
  end
end

Unit style でどこまで複雑なテスト設計に対応できるかは置いておいて、ちょっとした便利ネタでした。

Docker + Rails開発環境Tips

普段なんとなくで設定していたのですが、今の所こんな感じでやるのがいいんじゃない?というのをそろそろまとめたくなったので書いてみました。 もっといい方法があれば教えてください〜。

bundle install の実行のたびにDockerイメージのビルドし直しになるのを回避する

Quickstart にあるような構成では、以下のように Dockerfile で bundle install する。

FROM ruby:2.5.3

RUN mkdir /app
WORKDIR /app

RUN gem install bundler
RUN bundle install

この構成はgem一式を含めてポータブルにするという意味では合理的なのだが、開発環境においてはそうでもない。なぜなら、開発環境ではGemfileの更新やgemのアップデート、Dockerfileの修正が頻繁に発生し、そのたびに各開発者のローカルマシンでのイメージのビルドが必要になってしまうからだ。

これを回避するには、イメージの外、つまりコンテナで bundle install を行って gem を保存すればよい。ただし、コンテナを破棄した際に gem も消えてしまうと困るので、キャッシュできる必要がある。そのためには以下の方法がある。

  • bundle install 用のディレクトリをホストと共有し、そこに格納する
  • gem 用の volume を用意し、そこに格納する

前者のほうがお手軽だが、後者のほうがディスクアクセス的に有利そうではある(未計測)。もしホストと共有したくないとか、パフォーマンス上問題になってきたら後者に乗り換える形でどうだろうか。

bundle install をコンテナで行い、そのディレクトリをホストと共有する

BUNDLE_PATH でインストール先をホストと共有するディレクトリ(この場合は /app 配下の /app/vendor/bundle)に指定。

FROM ruby:2.5.3

ENV APP_PATH=/app
ENV BUNDLE_PATH=$APP_PATH/vendor/bundle

RUN bundle config path $BUNDLE_PATH

なお、 Bundler は BUNDLE_PATH , .bundle/config の順で優先してパスの設定を読み込む。そのためどちらかを指定していれば問題ないが、まれに .bundle/config の設定がないとRailsrequire 'bundle/setup したときに BUNDLE_PATH を見てくれないことがあった。そのため上記の例では両方設定している(原因特定できておらず、環境要因かもしれないので要確認)。どの設定が効いているかは docker-compose run --rm app bundle config で確認できる。

docker-compose.yml は以下のように /app 配下をホストにマウントする。 vendor/bundledelegated フラグ付きでマウントすると高速に同期できる(ただし、コンテナ→ホストへのWriteパフォーマンスが犠牲になる。bundler配下ではほぼ発生しないので問題なし)

version: '3'

services:
  app:
    build: .
    command: ['./bin/rails', 's']
    tty: true
    stdin_open: true
    ports:
      - '3000:3000'
    volumes:
      # cached/delegated options for performance tuning
      - .:/app:cached
      - ./vendor/bundle:/app/vendor/bundle:delegated
      - ./node_modules:/app/node_modules:delegated

gem 用の volume を用意し、そこに格納する

BUNDLE_PATH はマウントされないところにしておく。

ENV APP_PATH=/app
ENV BUNDLE_PATH=/bundle
RUN mkdir $APP_PATH
WORKDIR $APP_PATH

そして docker-compose.yml でボリュームを用意し紐付ける。

version: '3'

services:
  app:
    volumes:
      - bundle:/bundle
volumes:
  bundle:
    # use default driver

binstub も考慮したい場合は、以下のようにすると良いらしい。これがなくても手動で binstub を生成する(そしてリポジトリに含める)ことは可能な気がするが、この方法の便利なところは entry point を定義しておくと docker-compose up のたびに最新の状態に保てることだろう。そういう意味では、 bin/setup を entry point に登録しておくと便利なのかもしれない。

https://medium.com/@jfroom/docker-compose-3-bundler-caching-in-dev-9ca1e49ac441

デバッガによる対話コンソールを有効にする

よくある docker-compose.yml では、以下のように docker-compose upRailsサーバも一緒に起動するようになっている。

services:
  app:
    build: .
    command: ['./bin/rails', 's', "-b", "0.0.0.0"]

この設定だと標準入力が閉じられているので、 binding.prybinding.irb のような対話コンソールによるデバッグが行えない。従って以下の設定を追加する。

services:
  app:
    build: .
    command: ['./bin/rails', 's', "-b", "0.0.0.0"]
    tty: true
    stdin_open: true

ただし、 docker-compose up でコンテナを起動した状態では、デバッガが起動した内容のログを確認できても、対話コンソールにアクセスできない。Railsサーバのコンテナは docker-compose up のプロセスの後ろにいるためのようだ。従って一工夫する必要がある。2通りの方法を紹介する。

Railsサーバのコンテナに attach する

docker attach コマンドを使うと、起動中のコンテナの標準入出力に接続することができる。これをRailsサーバのコンテナに利用する。具体的には次の操作を行う。

  1. デバッガのブレークポイントを仕込んで、そこを通る処理を実行する(処理を通って対話コンソールが待機状態になっているかどうかは docker-compose up のログ、もしくは docker-compose logs でも確認できる)
  2. 別のターミナルで docker attach $(docker-compose ps -q app) を行って接続。接続直後は何も出力されないので、エンターキーを押して対話コンソールが起動していることを確認すると良い
  3. デバッグを行う
  4. 対話コンソールを終了する(ctrl-dquit などで)
  5. コンテナへの接続を解除する。 ctrl-p ctrl-q を連続して入力(デフォルトの設定。 docker attach --detach-keys="<sequence>" で変更可能)。うっかり ctrl-c を押してしまうとコンテナごと終了してしまうので注意

このように、Dockerを利用せずにローカルでサーバを起動する場合とは全く感覚が異なる。特にチームで作業する場合などでは、効率を上げるためにも bin/attach のようなスクリプトを作っておくと良さそうだ。

#!/usr/bin/env bash
echo attach to $1 ...
docker attach --detach-keys="ctrl-c" $(docker-compose ps -q $1)

次のような起動スクリプトでさらにラップしても良い。

docker-compose up -d
bin/attach app

Railsサーバのコンテナだけ docker-compose up とは別に起動する

attach を利用する方法で以下のような懸念がある場合には、Railsサーバを独立したコンテナで起動すると便利だ。

  • bin/attach のようなスクリプトを作っても、意識のアップデートが必要。Dockerに慣れていない場合にハードルがある
  • Railsサーバのコンテナに変更や試行錯誤が多く、再起動する機会が多い
    • up -d で起動して stop appstart app で個別に再起動することはできるが、フォアグラウンドで起動、終了を制御したい

このためには、まず docker-compose.yml で次のようにRailsサーバを起動しないようにする。ここではかわりに bin/update を実行して環境の最新化を行うようにしている。

services:
  app:
    build: .
    command: ["./bin/update"]

そして、Railsサーバは次のようなスクリプトで起動する(Makefileに入れるのが楽だ)。

docker-compose up -d
./bin/sleep_until_app_ready
docker-compose run --rm --service-ports app bin/rails s

注意点は —service-ports オプション。 docker-compose.yml で設定した ports が、 run のときにはこのオプションがないと反映されない。

https://docs.docker.com/compose/reference/run/

The second difference is that the docker-compose run command does not create any of the ports specified in the service configuration. This prevents port collisions with already-open ports. If you do want the service’s ports to be created and mapped to the host, specify the --service-ports flag

途中で使っている ./bin/sleep_until_app_ready は以下のような簡単なスクリプトで、 bin/update が終了するのを待っている。

#!/usr/bin/env bash

while :; do
  sleep 1

  docker-compose exec db echo 'alive?' &>/dev/null
  DB_UP=$?

  docker-compose exec app echo 'alive?' &>/dev/null
  APP_UP=$?

  if [ $DB_UP -eq 0 ] && [ $APP_UP -eq 1 ]; then
    break
  else
    echo -n "."
  fi
done

echo "Ready for running app"

対話コンソールで利用されるページャ

ruby イメージはデフォルトでは less を備えていないので、デバッガは ruby 実装の自前ページャを利用する。ローカルで動かしたときのように less で見たい場合は、インストールするように Dockerfile を修正すると良い。

Springサーバーを有効にする

spring-docker-example が参考になる。

基本的には以下のようにSpringサーバ用のコンテナを立てて、

services:
  app:
    build: .
    volumes:
      - .:/app:cached
    depends_on:
      - db
      - spring

  spring:
    build: .
    volumes:
      - .:/app:cached
    command: ["./bin/spring", "server"]

spring.sock をコンテナ間で共有するだけ。そのために、 sock ファイルを tmp ディレクトリ配下(ホストにマウントして共有)に置くように、 config/spring_client.rb (Springが起動時に読み込む)でその場所を教えることにする。環境変数なので、もちろん他の方法で指定しても良い。

ENV["SPRING_SOCKET"] = "tmp/spring.sock"

コンテナをまたいだ spring の自動立ち上げはできない(方法あったら教えてほしい)ので、適宜 depends_on: spring を設定しておくと良い。

注意したい点として、 Springサーバのコンテナの環境変数を、Railsサーバのコンテナの環境変数と揃えておくこと。Springサーバのコンテナが異なる環境変数を利用し、それを元に各種定数を初期化してキャッシュすると、Railsサーバは異なる環境変数を元にした定数を参照することになる。例えば database.yml にERBで環境変数を埋め込んでいる場合に、意図通りに設定されない可能性がある。

default: &default
  host: <%= ENV.fetch("DATABASE_HOST") { 'localhost' } %>

同様の理由で、マウントするディレクトリやボリュームも同じ条件にしておくのが安全。Spring経由での Dir.glob の結果が異なることがあるため。

なお、 spring-docker-example の例では、ホストとコンテナの両方で同じ spring.sock を共有し、さらに SPRING_SERVER_COMMAND='docker-compose up spring' を設定したりPIDのネームスペースをホストにしたりして、ホストからSpringを利用して bin/rails c を行うことができるようにしている(というか、そもそもホストにRubyとSpringを入れて起動するのを前提にしているようにみえる)。ホストとの共有はまだ試したことがなくて、きっと spring コンテナの環境での Rails コンソールが立ち上がると思うのだが、本当に macOS 上の環境に依存しない( native extension の違いとか、 webpacker が実行する yarn check --integrity の結果とかの影響を受けない)のか気になるところ。今のところはホストからの利用はせずにコンテナ上で完結するように設定しているが、そのうち試したい。

「現場で使える Ruby on Rails 5速習実践ガイド」の執筆に参加して現場の知見を書きました

この度、2018/10/19にマイナビ出版から発売される書籍「現場で使える Ruby on Rails 5速習実践ガイド」の執筆に参加しました。

書籍情報

今ご購入いただくと、購入特典として未収録PDFがもらえます!

https://book.mynavi.jp/pcbook/blog/detail/id=97187

特典は紙・電子本両方に付きます。配布は2018年10月24日(水)ごろになる予定です。

どんな本なの?

Ruby on Rails の基本的な使い方の解説から、複数人での開発やメンテナンスしやすい状態の維持などの実践的なトピックにまで広くカバーしています。

想定読者の中心を「他言語でのWebアプリケーション開発経験のある方」として設定していますが、初心者の方でも理解しやすいよう段階的に学べる構成に仕上げました。その結果480ページと盛り沢山なボリュームとなっており、索引から知りたい箇所を調べるといった辞書的な用途にも十分使えるかと思います。

本書の特徴

タイトルにもある通り、現場で得た知識や経験をところどころに散りばめています。例えば、チームでアプリケーションを開発するときにどうコードを共有してコミュニケーションを取るのか、長く生きることになりそうなアプリケーションの保守性をどう持続して行くのかという話題について、多くのページを割いて丁寧に説明しています。Railsを学習する最初のステップから発展して、実際に仕事で使うような次のステップでも本書が役に立つと思います。

読者が本書を超えて次のステップに進めるように、というのは特に重視した点です。そのための仕掛けとして、本書で解説はしないけれども大事だという概念はキーワードだけ出してみたり、脚注で補足したりと、興味があれば自力で調べて学習していけるようなきっかけを作っています。またRailsGuidesやAPIリファレンスなどを都度参照するようにして、Railsコミュニティの信頼できる情報ソースを見る習慣を付けられるようにもしています。

Rails 5.2 かつ Ruby 2.5.1 と、今出ているバージョンの最新に追従している点もアピールしたいところです。ActiveStrage や Credentials, Content Security Policy, Webpacker といった最近のRailsの機能にも触れています。「数年間Railsからちょっと離れちゃったけど、最近のRailsについて包括的に勉強し直したい」といった用途にも有用です。

逆に本書で扱っていない話題は、Railsアプリケーションの運用です。本当は触れたかったところではあるのですが、あくまでRailsの機能やRailsアプリケーションの作り方にフォーカスする形で限られた紙面を使いました(それでもなかなかのボリュームになってしまったのですが)。運用のために利用できるRailsの機能は紹介していますが、どこにどうやってデプロイするかといった話題は他の良書で学んでもらえたらと思います。

いくつかサンプルを貼るので参考にしてください。2色刷りで図もコードも見やすくなっています!

f:id:upinetree:20181016181506j:plainf:id:upinetree:20181016181348j:plainf:id:upinetree:20181016181341j:plainf:id:upinetree:20181016181349j:plain

個人的な担当範囲と感想

2章、6章、8章、9章、10章を中心に関わりました。特に10章は本書の特色を仕上げる章にしたくて中心的に力を入れました。

執筆する上で意識したのは、Railsらしさとはなんだろうというところから、Railsらしく書くことのメリット、それを外れるときの判断基準やリスク、その対処方法、Railsの外の設計パターンとRailsの取った道…などなど、いろいろ考えました。なんとなく理解していてもここまで突き詰めて考えたことはなかったので、執筆する中で自分としてもとても勉強になりました。Railsのコードも結構読んだので、この処理はあの辺ね〜という脳内地図ができたのも収穫のひとつです。

あとは、なるべくコンテキスト依存の単語を使わないようにしようとか、平易な言葉で説明しようということを意識しました。オブジェクト指向ソフトウェア工学をやった人には「関心事」「結合度」「オブジェクトの責務」などの表現がすごく便利で話が早いのですが、今回はRailsの学習に集中するために極力使わないようにしてみました。意識してみて、自分がいかに普段特定のコンテキストに生きているのかを感じました…。

苦労した点

たくさん苦労しました。

Railsが(というかウェブアプリケーションが)対象とする範囲が広く、この概念を説明するにはこれがいる、というのがとても多いので、「あー、あれの説明がないからこれを紹介できない!」となることが多かったです。互いに関連しあっている話題もあり、そのうえ複数人で執筆していることから調整が難しいという点も要因の1つでした。

そして、この話題はこの章に移動したほうが良いなど、読者の理解の順や話題の類似性などを考慮して組み替えることも多々ありました。しかしただ組み替えただけでは、それぞれ独立した話題が寄せ集まっただけで流れが悪くなってしまいます。そのためそこにストーリーを付ける必要があるのですが、それがなかなかに苦労しました。特に10章は難しかったのですが、(共著者の)大場さんの力をかなり借りてとても良い形にまとまったと思います。

また、説明したいことはいろいろと思い浮かんでも、それを端的に分かりやすく伝えるためのサンプルコードを考えるのに苦労しました。悩んだ末「これだ!」と思いついた例が、帯に短し襷に長しであったり、抽象的すぎたり具体的すぎたりファンタジーすぎたりと、ちょうどよいのが思い浮かばない。これはある種のトレードオフスライダーみたいなもので、結局ある程度の落とし所を見つけるのですが、ちゃんと伝わりやすくなっているかなと今でも心配です。これが一番大変だったかもしれません。

おわりに

こういった苦難を乗り越えてようやく出版されることになり、とっても清々しい気持ちです。まだまだブラッシュアップできるんじゃないとか、やりきれていないんじゃないかといった自問もありますが、そうやってると一生終わらないので、今はとにかく終わってよかったという気持ちです。といいつつ、手元に届いた見本誌を見ると、良い本に仕上がったんじゃないかなと思っています!

以上のように、現場の知識や経験をこねくり回して濃縮したのが「現場で使える Ruby on Rails 5速習実践ガイド」です。ぜひ手にとってみてください。

合わせて読みたい

t2os.hatenablog.com

ppworks.hatenablog.jp (早速のレビューありがとうございます!)