渡り鳥の旅路

元半導体系エンジニア、今Webエンジニアの雑記

#ginzarails 「プログラマがコードを書きながら考えること 」by jnchitoさんの観察ログ

はじめに

2019/8/29にDeNAさんにて開催された銀座Rails#12で、jnchitoさんのライブコーディング(動画)を観る機会があった。まずは雑に出す。

ginza-rails.connpass.com

当日の様子はこちらのハッシュタグでどうぞ

ライブコーディングが始まる前に思い浮かべたこと

  • どこから始めるか?
  • どんな出力にするか?
  • ツールは何を使うのか?
  • 伊藤さんならもちろんテストから?
    • もしかして簡易ツールだとテストは書かない?

パッと見ポイントだなと思ったこと

  • 使い慣れた技術を選定している
    • Rails
    • Heroku (w/ Scheduler)
    • Mechanize gem

→(後からわかるが)Mechanize gemはそうでもなかったらしい。

観察スタート(心の声を添えて)

序盤

  • 対象のサイトをよく観察してみる
  • 単純なターゲットを決める(ユニークキーをみつける)
  • 新プランの判断は既存との差分で決める

  • 名前に迷う(ある)

  • 名前をつけるときにちゃんとスペルをチェックしている

  • リポジトリを作成したら、まずは基本動作をチェックしてイニシャルコミットする(ある)

  • モデルを考える

    • Rubymineを利用して作成する(便利!)
    • 最初にすっとインデックスも貼っている
    • migrateもRubyMine上からやっている
    • 最初にバリデーションもさっと設定
    • コミットもRubymine上で実施。
    • 英語のまま

中盤

  • まずモデルからメソッドをはやしていく

    • やっぱりテストから作成している。
    • 簡単なテストをパスさせるところから
  • Gemをどこに追記してくか、いつも悩む(ある)

    • Mechanize導入して、最初に簡単な動作確認をする(重要)
  • 何度もリクエストを飛ばさないようにするためのgem(スクレイピング時の配慮大事)

    https://github.com/vcr/vcr

  • テストライブラリはどちらも使えるようにしておくと便利らしい

    • Minitest & RSpec
  • まずさっと試す→さっとリファクタ

  • DOMチェックはChrome Dev toolのconsoleでさっと試す

    • console上で使えるメソッドにも色々便利なものがある
  • Rubyの使い方についてはかなりサクサクでてくる(当たり前だけど)

  • 正規表現の適用までもかなりスムーズ

  • RubyMine上でgit diffも確認できる(diffの確認はやっているがいつもターミナルだなぁ)

  • アプローチとして、アーキテクチャ上の一連の処理に対して簡単なものをまず作る

    • インクリメンタルに実装を進めていく。
  • RubyMine上のターミナル画面を小さいまま使ってる(意外だがそうならざるを得ない?)

  • 自分とやっている手順は近いがRubyMine上ですべて完結しているところが凄い(ウィンドウの切り替えがないところが良い)

  • RubyMine上だとテストランもわんぽちでいける

終盤:運用へ向けて

  • Rakeタスクを作成
  • Heroku Schedulerを設定

まとめ

  • 手慣れているツール使いのスムーズさが半端ない(Ruby、RSpec、RubyMine)
    • 自分の中でここまで習熟しているものはないのでは、というくらいスムーズだった。
  • 自分の中であいまいなことは一次情報を調べる(英語、初めて/たまに触るツール)
    • この過程を経て手慣れたツールに昇華されていくのだと思う。

2019/9/8追記

伊藤さんが発表に使われた資料と動画がBOOTHで販売開始されました。リンクはこちら↓

jnito.booth.pm

【RailsでTDDを学ぶ】Rails 5 Test Prescriptionsの紹介

はじめに

7月から個人的にテスト強化月間をしているのですが、今読み進めているRails 5 Test PrescriptionsがRSpecでテスト駆動開発を学ぶ上で良い本なので紹介です。

そもそもなぜテスト強化をテーマにしているかというと、自社のメンターに「どこまでできたらプログラマーとして一人前なのか?」と聞いたことをきっかけとします。

「リファクタリングが身についたら」

答えはその一言でした。

ただ言葉としては非常にシンプルなのですが、この状況を作るにはいくつか条件が必要です。自分なりの答えはこんな感じです。

  • 扱う言語/フレームワークに習熟している
  • 設計の知識がある
  • 適切なテストを書いている
  • リファクタリングする時間を捻出できる(ある程度の実装スピードがある)

そもそもある程度の規模のプロダクトになると、リファクタリングする前提としてテストが必要なのです。

しかしながらその頃はテストに対してつらみしか感じておらず、義務駆動で書いている状況でつらいつらい、もっと楽しくテストを利用できないのかなぁと沈んだ気持ちでテストと向き合っていた頃にタイミングよく、Tama.rb会議で伊藤淳一さんがテストに関する発表をされることに!

blog.jnito.com

そのなかでで挙げていたテストの役割の6つ目、

設計を支援する

をみて「もしかしてこの考え方なら前向きにテストに取り組めるかも」とピピンッときて、これまた処方箋の6つ目

ちゃんと、もがき苦しんでますか?試行錯誤しまくってますか?

で「やっぱり強い人ももがいてきたからこそ今があるんだよな」となり、テスト熱が上がって動き出したのでした。

本の紹介

pragprog.com

前置きが長くなりましたが、本の紹介です。

RSpecの入門書であるEveryday Railsのあとがきで紹介されていてこの本を知りました (紹介文ではRails4版でしたが、Rails5版が出ています)。

実はAmazon kindleでも購入できるのですがThe Progmatic Bookshelfだと半額相当(〜2700円)で購入できるのでこちらがオススメです。

対象読者としては

  • Ruby/Railsの中級者以上
  • テストに関しては初心者でOK
  • テスト駆動開発(TDD)を身に着けたい人

になります。

この本では、最初にテストを書かない開発スタイルと、テスト書く開発スタイルを並べて、 時系列的にどのように開発コストが変わっていくかを、読者に想起させるところから始めます。

それからハードルの低いTDDの始め方を紹介し、各トピックに対して手法を比較しケースごとに向いている方法を実践していきます。一面的な見方ではなく、手法のメリット・デメリットに言及することで、読者が実践に適した手段を選べるように配慮されています。

目次

0. Preface
1. A Test-Driven Fable
2. Test-Driven Development Basics
3. Test-Driven rails
4. What Makes Great Tests
5. Testing Models
6. Adding Data to Tests
7. Using Test Doubles as Mocks and Stubs
8. Integration Testing with Capybara and Cucumber
9. Testing JavaScript: Integration Testing
10. Unit-Testing JavaScript
11. Testing Rails Display Elements
12. Minitest
13. Testing for Security
14. Testing External Services
15. Troubleshooting and Debugging
16. Running Tests Faster and Running Faster Tests
17. Testing Legacy Code

メモ(まだ途中なので徐々に増えます)

2. Test-Driven Development Basics

Where to Start

  • specify the initialization state of the objects or methods under test
  • happy path: a single representative example of the error--free version of the algorithm

どうするか迷ったら、 筆者はinitial state→happy pathの順をススめる。

The general form of an RSpec expectation is expect(actual_value).to(mather).

RSpecのBuilt in matcher https://relishapp.com/rspec/rspec-expectations/v/3-7/docs/built-in-matchers

The Second Test

所見だと戸惑いそうなやつ

One of my other favorite bits of RSpec is an implicit matcher 
that RSpec creates by name-mangling if you give it a matcher it doesn’t recognize. 

例えば Task.done?メソッドがあったとして、マッチャーとしてbe_doneを使える(RSpecが勝手に推測してくれる)。

3. Test-Driven rails

Let's Write some Rails

一度外側からアプリケーションをテストすることのメリット

There are several reasons why it’s valuable to have a test like this one that works from outside the application: 
  • ソースコードの内部構造を推定しなくてよい
  • ユーザー/クライアントから見えるfeatureについて考えることを強いてくれる。
  • 一連の動作をテストすることで、ユニットテストのギャップに潜むバグを抑制することができる。

A test with a view

はじめにゆるいviewのテストを書いて、あとでリファクタしながらタイトなテストにしていく。

This is a really common work pattern for me. 
Sometimes I have trouble seeing the shape of a view before I write it, 
so I write a very loose test and then tighten the test once I see 
what pieces of the view will exist for me to hook onto. 

5. Testing Models

A TDD Metaprocess

テストを追加する順番

  1. 初期状態
  2. シンプルな正常系
  3. 他の正常系
  4. 異常系、エッジケース

image.png (94.8 kB)

テストの重複

  • 事実の重複
  • ロジックの重複
  • 構造の重複

6. Adding Data to Tests

データを用意するための2つのテクニック

  • Fixtureを利用する
  • Factory toolを利用する

(テストダブルのチャプターでは完全に違う考え方をすることになるのだが)

全ての状況に対して完璧に答えてくれる方法はない。

どんなときにつらくなるか、想像してみる

Userに対するテスト 最初は

user = User.create!(date_of_birth: '2000-01-01')

で済んでいたのに、認証機能が入り、

user = User.create!(date_of_birth: '2000-01-01', emil: 'sample@gmail.com', password: 'password')

追加で取得する個人情報が増え、

user = User.create!(date_of_birth: '2000-01-01', emil: 'sample@gmail.com', password: 'password', hight: 170, zip_code: '9870012')

とどんどんデータの準備が増えていく、、

そのたびに壊れるテスト、、

Fixture

yamlを管理するのは大変だが、データを用意する速く簡単な方法には違いない。 テスト実行前に一気にデータを作成してくれる。いわゆるbefore(:suite)と同じ?

しかし、 例えばfixtureで一つのダメデータを作ると、テストが壊れてしまう。。

→Fixturesはglobal semantic dataがデータベースに必要なときに効力を発揮する。

Factory

Basic factory Creation

  • build(:project)
  • create(:project
  • attributes_for(:project):factoryの全てのattributesをハッシュで返す。コントローラテストでparamsを扱うときに便利。
  • build_stubbed(:project):この本で初めて知ったが便利そう

7. Using test Doubles as Mocks and Stubs

この章に書いてあることを最初から全て理解しようとするのはtoo muchな感じ

普段の開発では伊藤さんの記事を理解していれば十分では https://qiita.com/jnchito/items/640f17e124ab263a54dd

  • スタブとは? A stub is a fake object that returns a predetermined value for a method call without calling the actural method on an actual object.
# スタブはdoubleメソッドで作れるが、下記は特定のメソッドのみに適用するパーシャルスタブ
allow(thing).to receive(:name).and_return("Fred")
  • モックとは? A mock is similar to a stub, but in addition to returning the fake value, a mock object sets a testable expectation that the method being replaced will be called in the test. If the method is not called, the mock object triggers a test failure. expect(thing).to receive(:name).and_return("Fred")
# allowではなくexpectを使う
expect(thing).to receive(:name).and_return("Fred")

Mock Tips

  • Don't mock what you don't own

    • 自分のアプリが持つメソッドにのみテストダブルを適用し、(アプリからみて)外部メソッドに対しては適用しないこと(例:ActiveRecordのupdate_attributesメソッド)
    • そういうことをしそうになったら、自分のアプリ側にサードパーティのフレームワークを呼び出すメソッドを用意し、そのメソッドに対するスタブを作ること。
  • When to Mock, When to Stub

    • スタブを使うケース
      • テスト環境で作成が難しい/不可能なリアルなオブジェクトを用意したい時
    • モックを使うケース
      • 自分のコードの違うシステム間の連携をテストしたい時
      • モックはサブシステム間の境界をテストするのに向いている
      • 副作用を持っていたり、他のメソッドを呼ぶメソッドに対してモックを作る時は注意
      • モックはオリジナルのメソッドをバイパスする(=副作用や内部メソッドの呼び出しは再現しない)
  • Mocks Are Design Canaries

    • 一つのテストの中で多くのモックを使っている時は過分なテストをしているか、オブジェクト指向的に良くない設計になっていることを示唆している。

業務に取り入れてみて

この本はまだ読み途中なのですが、並行して業務でTDDを導入しています。

最初は1つ目のテストを通すまでに時間がかかり、実装までの初速が遅いなぁという感覚が強かったのですが、一度ベースとなるテストと実装ができるとそこからがはやいです。リファクタや機能の修正と併せてテストを回すことで、自分の変更に自信を持って開発を進めることができます。

Kent Beckの[テスト行動開発 付録C]に

テスト駆動開発は、実際に手を動かしてみないと理解が難しい技法です。
本書も、読んだだけでは深い得心には至らないでしょう。
しかし、テスト駆動開発の良さ、強みは手を動かせばわかります。
なぜなら、TDDの本質は精神状態のコントロール、不安と自信の制御にあるからです。
結果(書かれたコードとテストコード)ではなく、
過程(思考プロセスとリファクタリング)に本質があります。

と書いてあり、まさにその通りだなと思えるようになりつつあります。

まとめ

テスト関してまだまだ修練あるのみですが、実践することでリファクタしやすい状況ができるなと実感できました。よりスムーズに進められるよう色々実験していきます。

【ゆる輪読会録】[試して理解]Linuxのしくみ

はじめに

6~8月にかけて[試して理解]Linuxのしくみの輪読会をしているので、その紹介です(あと2回で終わりそう)。

きっかけはこちら

本の紹介

gihyo.jp

Linux上で実行する処理がどのように動くか?を手を動かして実験しつつ学んでいく本です。

Linuxでの簡単なオペレーションはできることを前提としています。

必須ではありませんがサンプルコードがC言語のため、C言語がわかると+αの実験を試しやすいです(というかC言語が分かりたくなります...!)

目次

第1章 コンピュータシステムの概要
第2章 ユーザモードで実現する機能
第3章 プロセス管理
第4章 プロセススケジューラ
第5章 メモリ管理
第6章 記憶階層
第7章 ファイルシステム
第8章 ストレージデバイス

進め方

ちょうどそのころ見かけた読書会記事のコンセプトが、今回の趣旨にちょうどよく、参考にさせていただきました。

scrapbox.io

雑に書くと、

「とにかく事前準備の負担を減らす。当日は本/PC/体だけ持っていけばOK」

というコンセプトで進めました。

場所取りしやすさを優先して、@makicamelさんの会社と自社の会議室を週末に借りて開催しました。

集合したら最初にアイスブレイクして、代わる代わる声を出して読み進めつつ、モブプロ的に実験をします。

準備がない分、(みんな大好き)esaに学んだことまとめつつ、実験結果をペタペタ貼りつつ進めました。

<最近出た推し機能>

ReleaseNotes/2019/08/05/同時編集が可能なEditor v2のオープンβテストを開始します - docs.esa.io

準備

事前準備の負担を減らす、と書きつつLinuxの環境は必要なわけで。当時Dockerの勉強もしていたので、練習がてらDockerで実験ができるよう輪読会向けリポジトリを作りました。

Dockerを入れてスクリプトを2つ叩けばすぐLinuxの実験ができるようになっています。

github.com

輪読会中は用意したコンテナ上で実験を進めていきました。6章以降で再現できないものもありましたが、概ね良い感じでした。

参加者はだいたい2-4人で小規模催行です。

振り返り

Keep

  • 開催のハードルが低く、かなり続けやすい。
  • わからないところはどんどん相談できるので理解が深まる。
  • 複数人でわちゃわちゃ実験するのは楽しい。
  • Dockerだと軽量で環境構築も簡単

Problem

  • その分野に詳しい人がいない回ではなかなか理解が進まない(輪読会のコンセプトと表裏一体ですが)
  • Dockerで全ての実験を再現できるわけではない。
  • アイスブレイクの近況報告が毎度長くなってしまうw

Try

  • より実践的なLinuxオペレーションも身に着けたい。
  • C言語、分かるようになりたい。

gihyo.jp

まとめ

雑に始めた輪読会でしたが、「ぜんぜんわからん分野をゆるく読書会する」方式、オススメです。

はじめてのRubyKaigi 予習編

いよいよ明日からRubyKaigiですね。

rubykaigi.org

今回RubyKaigiに初めて参加するので、事前に情報収集したことをまとめてみました。

少しでもRubyKaigiチョットワカルための手助けになれれば嬉しいです。

RubyKaigiについて

そもそもRubyってどんなカンファレンスなのだろう?ということについては、 RailsDM 2018 Day4のKeynoteでamatsudaさんが話されていたので、資料へのリンクを貼っておきます。

A RubyKaigi Talk - Speaker Deck

数あるカンファレンスが方向性を模索する中、技術的に最高の質を担保していくぞという意気込みを全面に押し出されています。

会場

今回福岡空港から博多駅まではかなり近いのですが、そこから福岡国際会議場は少し行きづらいなと思っていところ、 SmartHRさんが会場/福岡空港/博多駅/天神駅の区間でシャトルを出してくださるようです!

詳しくはこちら↓

SmartHR シャトルバスの乗り方 #RubyKaigi2019 (4月18日〜20日) | 株式会社SmartHR

Japan Taxiさんがタクシースポンサーなのでタクシー情報も探してみたのですが、あいにく見つけられず。見つけたら追記します。

昼の部:セッション

先日開催されたRejectKaigiの「RubyKaigi 2019タイムテーブル徹底解説」にて、@a_matsudaさん & RubyKaigi運営チームによる各スピーカー&セッションの紹介があったので、そのときのメモを添えて。

ちなみにRubyKaigiでは英語の発表があるのですが、通訳があるトラックとないトラックがあります。

トラック 場所 通訳
A Main Hall (3F) あり
B Multi-purpose Hall (2F) なし
C 409 + 410 (4F) なし
D International Conference Room (5F) あり

1日目 (4/18)

9:00- 受付

10:00-11:10

トラック 発表タイトル スピーカー メモ
A (3F) The Year of Concurrency Yukihiro "Matz" Matsumoto 【Keynote】Ruby3のなにか

11:20-12:00

トラック 発表タイトル スピーカー 資料 メモ
A (3F) Ruby 3 Progress Report Matz & the Ruby Core Team 資料 Ruby3の進捗レポート

12:00-13:30 ランチ

下のグルメ情報をチェック!

13:30-14:10

トラック 発表タイトル スピーカー 資料 メモ
A (3F) Performance Improvement of Ruby 2.7 JIT in Real World Takashi Kokubun 資料 MJIT, Railsも早くなる?
B (2F) How to take over a Ruby gem Maciej Mensfeld 資料 Rubyemsの乗っ取られをどう防ぐか (最近話題ですね)。本職がセキュリティの人
C (4F) Terminal Editors For Ruby Core Toolchain ITOYANAGI Sakura まだ Pure Ruby互換のライブラリ作った
D (5F) How to use OpenAPI3 for API developer ota42y 資料 SwaggerがOpenAPI3になる、Rackでうまく使えるように対応

参加予定:Ruby Gemのセキュリティの話が気になります。

14:20-15:00

トラック 発表タイトル スピーカー 資料 メモ
A (3F) Write a Ruby interpreter in Ruby for Ruby 3 Koichi Sasada まだ Ruby3向けのインタプリタ、Cで書いてた部分をRubyで書いた
B (2F) Determining Ruby Process Counts: Theory and Practice Nate Berkopec まだ Speed shopの人、GCパラメータの解説
C (4F) Pathfinder - Building a Container Platform in Ruby Ecosystem Giovanni Sakti まだ コンテナマネージャを自作した話
D (5F) Pragmatic Monadic Programing in Ruby joker1007 資料 Rubyの黒魔術、モナドを実装する試み

参加予定:迷い中。。

15:00-15:40 おやつタイム

15:40-16:20

トラック 発表タイトル スピーカー 資料 メモ
A (3F) A Type-level Ruby Interpreter for Testing and Understanding Yusuke Endoh 資料 型の話、VMをもう一個作る
B (2F) Compiling Ruby to idiomatic code in static languages Alexander Ivanov&Zahary Karadjov まだ トランスパイラ、例えばRubyで書いたライブラリをPythonで使える的な。型もつけられる
C (4F) Writing Debuggers in Plain Ruby! Fact or fiction? Genadi Samokovarov まだ Web consoleの作者、Pure Rubyでデバッガー
D (5F) Ruby for NLP Yoh Osaki 資料 Rubyで自然言語処理

参加予定:D

16:30-17:10

トラック 発表タイトル スピーカー 資料 メモ
A (3F) Fibers Are the Right Solution Samuel Williams まだ Fiber周りのコード、Rubyコミッタの最若手
B (2F) A Bundle of Joy: Rewriting for Performance Matthew Draper まだ Rails commiter、bundler遅いので書き直した(動くやつ)
C (4F) A Deep Learning Adventure Paolo Perrotta まだ メタプログラミングRubyの著者、Deep learning本書いた(イントロ的な内容になりそう)
D (5F) RMagick, migrate to ImageMagick 7 Shizuo Fujita 資料 RMagickのメンテの話。予定より進捗遅れてるけど、色々やってるよ

参加予定:A

17:20-18:00

トラック 発表タイトル スピーカー 資料 メモ
A (3F) Pattern matching - New feature in Ruby 2.7 Kazuki Tsujimoto 資料 Pattern matching (今回のRubyKaigiの目玉)、Ruby2.7
B (2F) Building Serverless Applications in Ruby with AWS Lambda Alex Wood まだ AWS SDK Rubyのメンテナ、Ruby with Lambdaの話
C (4F) GraphQL Migration: A Proper Use Case for Metaprogramming? Shawnee Gao 資料 RubyのメタプロでGraphQLを使いこなす
D (5F) Compacting GC for MRI v2 Aaron Patterson 資料 Compacting GC for MRI v2 (タイトルそのままや。。)

参加予定:A

2日目 (4/19)

8:30-10:00 朝食

2日目の朝はRubyKaigi会場とお隣の福岡サンパレスホテルで朝食をいただけます。

Official Breakfast sponsored by Medley

Stripe - RubyKaigi Breakfast with Stripe

10:00-11:10

トラック 発表タイトル スピーカー メモ
A (3F) All bugfixes are incompatibilities nagachika 【Keynote】ガッツリな話

11:20-12:00

トラック 発表タイトル スピーカー メモ
A (3F) How RSpec works Sam Phippen RSpecメンテナ
B (2F) Six Years of Ruby Performance: A History Noah Gibbs おなじみ?のノアコーナー、Rubyのパフォーマンスの話
C (4F) Practical mruby/c firmware development with CRuby Hitoshi HASUMI (メモりそこないました。。)
D (5F) Better CSV processing with Ruby 2.6 Kouhei Sutou & Kazuma Furuhashi CSVのパフォーマンスの話

参加予定:D, RubyData関連でCSV気になります。

12:00-13:30 ランチ

下のグルメ情報をチェック!

13:30-14:10

トラック 発表タイトル スピーカー メモ
A (3F) intimate Chat with Matz and mruby developers about mruby Hiromasa Ishii mruby漫談
B (2F) Zeitwerk: A new code loader Xavier Noria Zeitwerk (Rails6に入る)、A new code loader
C (4F) Yabeda: Monitoring monogatari Andrey Novikov ロシア方面出身の火星人?、Rubyのモニタリングの話
D (5F) Ovto: Frontend web framework for Rubyists Yutaka HARA Ovto、るびまに予習資料あり

参加予定:B

14:20-15:00

トラック 発表タイトル スピーカー メモ
A (3F) State of Sorbet: A Type Checker for Ruby Jake Zimmerman & Paul Tarjan Stripe with Sorbet、今年OSS化
B (2F) Actionable Code Coverage Michael Grosser Coverageライブラリの話
C (4F) RubyData Workshop RubyData team ワークショップ、おやつタイムまでぶちぬき、おすすめ
D (5F) Terminal curses Shugo Maeda Rubyでテキストデータ、cursesの話、時代はTUI

参加予定:C, RailsDMでの発表を聞いて以来RubyDataが気になっているので、ワークショップに出てみようと思っています。

15:00-15:40 おやつタイム

15:40-16:20

トラック 発表タイトル スピーカー メモ
A (3F) A light weight JIT compiler project for CRuby Vladimir Makarov Stripe with Sorbet、今年OSS化
B (2F) Building a game for the Nintendo Switch using Ruby Amir Rajan Swithのゲームをmrubyで作った
C (4F) Crystalball: predicting test failures Alex Rodionov Celenium driver gemのメンテナ、テスト回した時にどこを通ったかを紐付ける。リグレッションテストを効率的に回す。期待度かなり大
D (5F) The fastest way to bootstrap Ruby on Rails Uchio KONDO Rubyでコンテナ

参加予定:C

16:30-17:10

トラック 発表タイトル スピーカー メモ
A (3F) Benchmarking your code, inside and out Emily Stolfo elastic searchの中の人、ベンチマークとパフォーマンスの話。かなり規模がでかいやつ
B (2F) Beyond puts: TruffleRuby’s Modern Debugger Using Chrome Kevin Menard これすごそう。 ChromeのDev toolを使ってRubyのデバッグをできるようにする
C (4F) Building Homebrew in Ruby: The Good, Bad and Ugly Mike McQuaid Homebrewのメンテナ、ver2.0のお披露目の話?
D (5F) What is Domain Specific Language? Tanaka Akira DSLとはなにか?、DSLと普通のライブラリの違いにもんもんとしていたが納得できる結論がでた

参加予定:A or C

17:20-18:30

トラック 発表タイトル スピーカー メモ
A (3F) LT LT LT

3日目 (4/20)

8:30-10:00 朝食

3日目の朝はRubyKaigi会場で朝食をいただけます。

Official Breakfast sponsored by Medley

10:00-11:10

トラック 発表タイトル スピーカー メモ
A (3F) Ruby Committers vs the World CRuby Committers ぐだぐだやるw

11:20-12:00

トラック 発表タイトル スピーカー メモ
A (3F) (partially) Non-volatile mruby Yurie Yamane(team yamanekko) & Masayoshi Takahashi スタティックなmruby
B (2F) Fuzzing native Ruby code with Kisaten Ariel Zelivansky Fuzzing、すごくテッキーになりそう
C (4F) The Selfish Programmer Justin Searls すごくいい話?
D (5F) Cleaning up a huge ruby application Sangyong Sim one shot coverage、実際に使われていないコードを削除

参加予定:D

12:00-13:30 ランチ

下のグルメ情報をチェック!

13:30-14:10

トラック 発表タイトル スピーカー メモ
A (3F) The challenges behind Ruby type checking Soutaro Matsumoto type、去年の続き
B (2F) JRuby: The Road to Ruby 2.6 and Rails 6 Charles Nutter & Thomas E Enebo JRuby on Rails6
C (4F) Running Ruby On The Apple II Colin Fulton 16bitでRubyをコンパイル(8bitでもいける?)
D (5F) Best practices in web API client development Go Sueyoshi APIクライアントの話

参加予定:D or A

14:20-15:00

トラック 発表タイトル スピーカー メモ
A (3F) The future of the Bundled Bundler with RubyGems Hiroshi SHIBATA RubyGems, Bundlerの未来
B (2F) Pre-evaluation in Ruby Kevin Deisz 事前実行で最適化
C (4F) dRuby 20th anniversary hands-on workshop Masatoshi SEKI dRubyのワークショップ(おやつの時間打ち抜きでやる)
D (5F) Performance Optimization Techniques of MessagePack-Ruby Sadayuki Furuhashi MessagePack、世界最速オーサライズシリアライゼーションプロトコル

参加予定:B or D

15:00-15:40 おやつタイム

15:40-16:20

トラック 発表タイトル スピーカー メモ
A (3F) Reducing ActiveRecord memory consumption using Apache Arrow Kenta Murata pluckを使ってメモリ使用量を削減
B (2F) Ruby Serverless Framework Tung Nguyen Ruby on Jetsの作者(Lambdaで動くRailsみたいなやつ)
C (4F) Play with local vars Tatsuhiro Ujihisa Rubyのローカル変数面白いよ
D (5F) Timezone API nobu Timeにゾーンの情報をもたせるよう変更した

参加予定:A or C

16:30-17:10

トラック 発表タイトル スピーカー メモ
A (3F) The send-pop optimisation Urabe, Shyouhei 今回一番テッキーな話。rubyの返り値を無視させると、色々最適化できる
B (2F) TruffleRuby: Wrapping up compatibility for C extensions Petr Chalupa TruffleRuby、Javaで書かれているRubyがClangで動く
C (4F) Working towards Bundler 3 Colby Swandale 未来のBundlerの話
D (5F) Red Chainer and Cumo: Practical Deep Learning in Ruby Naotoshi Seo & Yusaku Hatanaka GPU

参加予定:A

17:20-18:30

トラック 発表タイトル スピーカー メモ
A (3F) Optimization Techniques Used by the Benchmark Winners Jeremy Evans 【Keynote】sequel、loader(恐ろしく早いフレームワーク)、ellvis、テクニカルな話

クロージング

夜の部:パーティ

RubyKaigi前日から、毎夜どこかでイベントがあります。 公式パーティ以外は申込みが必要です。

Parties - RubyKaigi 2019

RubyistはKaigi後、川に集まる習性があるらしいです。。 デカ外人さんにも会いたい人は川情報をお見逃しなく。

去年の様子↓

アフターイベント

RubyKaigi翌日にもイベントがあります。 僕はランニングイベントに申し込んだので、頑張って早く起きねば!

rubykaigi5k.connpass.com

fukuokarb.connpass.com

グルメ情報

tech.smarthr.jp

mrubyforum.blogspot.com

mrubyforum.blogspot.com

まとめ

色々てんこもりな4日間、とても楽しみです!!

【振り返り】GCJ2019 Round 1A: Pylons

今日はGoogle Code Jamの3回あるRound1のうちの初日でした。

先週末の予選を終えてからAtcoderに登録し簡単な問題を解いてみたのですが、 流石に1週間でRound1をパスできるほど甘くなかったです^^;

マス目を埋める問題は初見だったので、"マス目 競技プログラミング"でググりつつ「DPとは。。」という気持ちになり、 これは素手じゃ戦えんなと悟りPCを閉じて走りに行きました(完)

とこれだけでは何も残らないので、競技プログラミングの先輩が公開しているコードをRubyで書き直しつつ振り返っていきます。

問題概要

  • R行C列のマス目が与えられる
  • 全てのマス目を1回ずつ通る道順を求める
  • 次に移動するとき、今のマスから見て前後斜め直線状のマスを選ぶことはできない (チェスならクイーン、将棋なら飛車+角行が移動できる位置)
  • 実現できない場合は"IMPOSSIBLE"、できる場合は"POSSIBLE"を返し道順を出力する

制限

  • 時間:20sec / テストセット
  • テストセット1: T=16, 2≦R≦5, 2≦C≦5
  • テストセット2: 1≦R≦100, 2≦R≦20, 2≦C≦20

コードの解析

今回もすでにけんちょんさんが記事をアップしていたので、ありがたく拝読させて頂き、まずはRubyに焼き直してみました。

GCJ 2019 Round 1A A - Pylons - けんちょんの競プロ精進記録

ちなみに今回採用すべき解法はDPではないらしく、GCJの解説によるとKnight's tourというチェスのナイトのような動き(将棋だと桂馬)を採用したアルゴリズムが1つの解のようです。

# ルート生成
def route_generator(h, w)
  # ダメなパターンを先に除外
  return false if h == 2 && w < 5
  return false if h == 3 && w < 4
  return false if h == 4 && w < 4

  # ルートを作る
  arr = route(h, w)

  # 対称なグリッド対策
  if (h % 2 == 0) && h == w
    arr = avoid_conflict(h, w, arr)
  end

  arr
end


def route(h, w)
  arr = []

  (0...w).each do |j|
    (0...h).each do |i|
      if i % 2 == 0
        arr << [i, j]
      else
        (h == 2) ? arr << [i, (j + 3) % w] : arr << [i, (j + 2) % w]
      end
    end
  end

  arr
end

def avoid_conflict(h, w, arr)
  p = arr[h*w - h]
  arr.delete_at(h*w - h)
  arr << p

  arr
end

# 解答のための形作り
def answer_formatter(h, w)
  answer = ""
  swapped = false

  if h > w
    h, w = w, h
    swapped = true
  end

  if arr = route_generator(h, w)
    answer << "POSSIBLE\n"
    arr.each do |el|
      if swapped
        el[0], el[1] = el[1], el[0]
      end

      answer << "#{el[0]+1} #{el[1]+1}\n"
    end
  else
    answer << "IMPOSSIBLE\n"
  end

  answer
end


t = gets.chomp.to_i

t.times do |i|
  h, w = gets.chomp.split(" ").map(&:to_i)
  answer = answer_formatter(h, w)
  puts "Case ##{i + 1}: #{answer}"
end

アルゴリズム

公式の解説を読むといくつかアルゴリズムが紹介されていました。 力任せ探索と乱択アルゴリズムは、時間が許せばそのうち結果が出るが、問題によっては計算量が爆増してしまうため最後のテストセットまでクリアできないことが多そうです(現実問題では札束で殴って許されるケースもありますが、、)。

  • Brute-force search (力任せ探索)
  • Randomized algorithm (乱択アルゴリズム)
  • Dynamic Programming (DP、動的計画法)
  • Greedy Algorithm (貪欲法)

動的計画法と貪欲法については、これから勉強していく予定です。

動的計画法の導入としては下記のブログで、パフォーマンス的な利点も含めてわかりやすく説明されていました。

動的計画法(Dynamic Programming)をサルでも分かるように説明する - その1(フィボナッチ数列) - ベルリンのITスタートアップで働くソフトウェアエンジニアのブログ

まとめ

さっそくアルゴリズムの壁に直面したので、下記記事を参考に修行していこうという機運が高まりました。 Round 1Bではもう少し良い結果を出せるように頑張ります。

qiita.com

また今回もC++のコードを読解したのですが、リファレンスが利用しやすくて思ったより捗りました。あとRuby書くの楽すぎるでしょ!という気持ちも高まりました笑

PG::NotNullViolation: ERRORを解消する

DBにとあるレコードを保存しようとしたところ、下記のエラーにハマったのでそのメモ。

ActiveRecord::NotNullViolation: PG::NotNullViolation: ERROR:  null value in column "hoge_cd" violates not-null constraint
DETAIL:  Failing row contains (fuga, ccc, 2019-04-01, 2019-04-03).
: INSERT INTO "foo" ("bar_id", "hoge_type_cd", "created_at", "updated_at") VALUES ($1, $2, $3, $4,) RETURNING "id"

※テーブル構造やデータは若干修正しています

環境

  • 言語: Ruby 2.4
  • FW: Rails 5.1
  • DB: PostgreSQL

状況

  • hoge_typeに対してsimple_enumでenumを利用
  • shemaの定義は大丈夫そう
  • as_enumもモデルに記述済
# db/schema.rb

  create_table "foo", force: :cascade do |t|
    t.integer   "baar_id",             null: false
    t.integer  "hoge_type_cd",     default: 1, null: false
    t.datetime "created_at"
    t.datetime "updated_at"
  end
# app/models/foo.rb

class Foo < ActiveRecord::Base
  as_enum :hoge_type, {
      xxx: 1,
      yyy: 2,
      zzz: 3,
  }, prefix: true

end

結論

定義も大丈夫だしなんでエラーが出るんじゃ!と悶々してたんですが、 結論としてはhoge_enumに対してas_enumで定義していない値(今回はccc)を保存しようとしているのが原因でした。

# app/models/foo.rb

class Foo < ActiveRecord::Base
  as_enum :hoge_type, {
      xxx: 1,
      yyy: 2,
      zzz: 3,
      ccc: 4, # ここに追記
  }, prefix: true

end

辿り着くまでに見た記事など

Rails標準のenumとgemを使うのだとどちらがいいかは、今後調べたいです。

【WIP】【振り返り】GCJ2019 Qualification Round: You Can Go Your Own Way

今日は下記記事の2問目について少しずつ振り返りを進めていきます。

roo-ashi.hatenadiary.com

ちなみにGoogle Code Jamのサイトに行くと、今でもSubmitしたコードを採点してくれます。

今回もけんちょんさんの記事を参考にRubyで実装していきます。

GCJ 2019 Qual B - You Can Go Your Own Way - けんちょんの競プロ精進記録

本番でSubmitしたコード

def route_choice(str)
  route = ''
  rival_route = str
  while
  if check_last_motion(rival_route) == 'S'
    route.insert(0, 'E')
  else
    route.insert(0, 'S')
  end
    rival_route.chop!
    if rival_route == ''
      break
    end
  end
  route
end

def check_last_motion(str)
  str[-1]
end

def add_motion(route, motion)
  route.insert(0, motion)
end

t = gets.chomp.to_i

t.times do |i|
  n = gets.chomp.to_i
  str = gets.chomp
  route = route_choice(str)
  puts "Case ##{i + 1}: #{route}"
end

考え方がわかるとシンプルな実装になりますね↓

競技プロerにならったコード

def route_choice(str)
  route = ''
  
  (0...str.size).each do |letter|
    if str[letter] == 'E'
      route << 'S'
    else
      route << 'E'
    end
  end
  
  route
end


t = gets.chomp.to_i

t.times do |i|
  n = gets.chomp.to_i
  str = gets.chomp
  route = route_choice(str)
  puts "Case ##{i + 1}: #{route}"
end

ちょっと味気ないのでワンライナーにしてみました。 (もしかしてgetsするところも含めてワンライナーできるんでしょうか:eyes:)

ワンライナー

def route_choice(rival_route)
  (0...rival_route.size).inject('') {|route, idx| rival_route[idx] == 'E' ? route << 'S' : route << 'E'}
end


t = gets.chomp.to_i

t.times do |i|
  n = gets.chomp.to_i
  str = gets.chomp
  route = route_choice(str)
  puts "Case ##{i + 1}: #{route}"
end

まとめ

2問分の振り返りを通じて、一見数字や経路など情報量が多そうな対象をそのまま鵜呑みにせず、ただの文字列とみなすことで計算量を減らすのがコツなのだなぁと思いました。