スマホアプリ開発を支えるRuby (Burikaigi2020で発表できなかったもの)

経緯

2020/02/01 にBurikaigi2020というイベントがありました。

toyama-eng.connpass.com

その約1月前に、発表者に立候補し、年末年始などでちょっとずつスライドを作っていました。

が、イベントの5日前ぐらいから体調が悪くなり、3日前に検査してもらったらインフルエンザということが判明。
無理やり参加して、参加者に感染させるわけにもいかず、やむなくキャンセルとなりました。
(運営側にはご迷惑をおかけしました。。。)

スライドを作ったものの、他で発表する機会もないので、ブログにまとめてみようと思います。

スライドだけは、こちらにもアップロードしてあります。

speakerdeck.com

発表

f:id:suzaku114:20200208131609p:plain

スマホアプリ開発を支えるRuby」と題して、石倉が発表します。

f:id:suzaku114:20200208131632p:plain

アジェンダは、こちらのとおりです。

f:id:suzaku114:20200208132423p:plain

まず、自己紹介ですが、石倉といいます。
出身地も、現住所も富山県富山市ですが、所属している会社は東京にあります。
いわゆるリモートワークというやつで、この写真のような自宅の一室で仕事をしています。

興味範囲は幅がそれなりに広く、広く浅くいろいろやっています。

f:id:suzaku114:20200208132844p:plain

Toyama.rb には、ほぼ毎回参加しており、
Kanazawa.rb には、子供が生まれる前後ぐらいから、なかなか参加できていないです。。

f:id:suzaku114:20200208133000p:plain

個人的な活動としては、この画像のような、ちょっとしたゲームアプリなどを開発・リリースしています。
興味範囲の広さを利用して、複数のプラットフォームで、個別に実装しています。

f:id:suzaku114:20200208133200p:plain

モンスター・ラボという会社に所属しています。
先程あったように、本社は東京の恵比寿にありますが、結局去年は1年間出社せずに仕事をしました。

会社としては、海外にも拠点がたくさんありまして、恵比寿の本社や、島根の拠点には外国籍のメンバーも多数います。

自分の所属している部署では、スマホアプリなどの受託開発をメインにやっていますが、
会社としては音楽配信だったり、RPAだったり、いろんなことをやっています。

f:id:suzaku114:20200208133447p:plain

ここから本題です。

f:id:suzaku114:20200208133510p:plain

Rubyと聞いて、一番印象が強いのは Ruby on Rails かと思います。

ですが、それ以外にもいろいろな場所で Ruby は活用されています。

今回は、 fastlane と Danger という、スマホアプリ開発に役立つツールを、事例として紹介します。

f:id:suzaku114:20200208134020p:plain

本日想定しているターゲットとしては、
Rails が書けるけど、それ以外にも活躍の幅を広げたい人、
スマホアプリのビルド周りで、手作業が多くて困っている人、
コードレビューのやり取りで、細かな指摘が多くて困っている人、などです。

f:id:suzaku114:20200208134235p:plain

まずは、 fastlane の紹介をします。

f:id:suzaku114:20200208134259p:plain

突然ですが、iOSのビルドやデプロイって辛くないですか?

そもそも、 ipa ファイルを作るのに、XcodeGUIでマウス操作をしないといけなかったり、
逆にコマンドでやろうとすると、いろんな引数を与えないと、ちゃんとビルドできなかったり。

また、他の人にアプリを渡す際にも、
手動で配布していると、毎回開発の手を止めないといけなかったり、
いろんな人にやってもらおうと思っても、Testflightの画面が変わってしまって、手順書が陳腐化、結局分かる人が作業する羽目になったり。

f:id:suzaku114:20200208134636p:plain

それを解決できるかもしれないのが、 fastlane というツールです。

これを使えば、例えばこのような記述を Fastfile というファイルに書いて、このコマンドを実行するだけで、
アプリのビルドからのTestflightへの配信ができます。

ただ、このコードはあくまでイメージなので、やっぱり多少の引数・設定などは必要になります。
ただ、 Xcode 付属のコマンドを直接実行するよりは、はるかにわかりやすいと思います。

f:id:suzaku114:20200208135041p:plain

先程 Fastfile に書いていた build_app などを、 fastlane では"アクション"と呼びます。

他にも、いろいろなアクションが、 fastlane では標準で用意されています。

f:id:suzaku114:20200208135220p:plain

資料作ったとき現在ですが、こんなに大量のアクションが用意されています。

よく使われそうなものをマークしてみました。

例えば、 deliver というアクションでは、 App Store に載せる説明文やキャプチャを管理して、 App Store Connect へのアップロードができます。

このような既存のアクションを組み合わせて、それぞれのプロジェクトにあったワークフローを作成することができます。

f:id:suzaku114:20200208135522p:plain

また、 fastlane のアクションは、それ自体はただのRubyのクラスです。

例えば、 build_ios_app は、このような定義になっています。

Action というクラスを継承して定義して、 run というメソッドを実装していますね。

f:id:suzaku114:20200208135828p:plain

つまりは、Ruby が書ける人は、独自のアクションが作れます。
独自のアクションが作れれば、社内独自の ipa のアップロード先へアップロードしたり、独自のシステムへの通知なんかもアクションとして作れます。

まぁ、ただ、 iOS 開発の知識がないと、行き詰まる場面は多いとは思います。。

f:id:suzaku114:20200208140139p:plain

実際に独自アクションを作ってみる場合ですが、こちらのドキュメントにやり方が載っています。

ざっくり説明すると、
雛形を作成するコマンドが用意されているので、それを実行すると"アクション名"をインタラクティブに聞かれます。
それに答えると、いい感じの場所にアクションの雛形が用意されるので、それに実装をしていきます。
最後に、 Fastfile の中でそれを実行するような記述を書けば、実際に動作させることができます。

f:id:suzaku114:20200208140519p:plain

Fastfile というファイルがこれまでも出てきましたが、こいつがビルドスクリプトとなります。

Fastfile 自体も、 Ruby で書きます。
最初に出してたイメージも、ブロックがあって、その中でメソッドをコールしていますよね。

プロジェクトに合わせた設定・フローや、アクションにするまでもない細かなスクリプトなどは、ここに直接記述できます。

これが Ruby で書けるので、ちょっとした処理がスマートに書けたりします。
事例を3つほど紹介します。

f:id:suzaku114:20200208141421p:plain

1つ目としては、 CircleCI 上で ipa ファイルを作成する際に、どのブランチに変更があったのかによって、利用する scheme を変更する例です。

CircleCI では、ビルド対象のブランチを環境変数として取得できるのですが、 Ruby では case が式なので、そのまま変数に代入できます。
あとは、それを build_app の引数に渡すだけで、好きな scheme でビルドさせることができます。

f:id:suzaku114:20200208141746p:plain

2つ目ですが、これも CircleCI 上で、Gitタグの作成を検知して、そのタグ名をアプリのバージョン名にする例です。

これも、タグ名を環境変数から取得することができるので、 set_info_plist_value というアクションに渡すことで、アプリの設定を書き換えることができます。

これを実行した後に build_app を実行することで、出力された ipa ファイルのバージョン名は、Gitのタグ名と同じにできます。

本来であれば、 XcodeGUI上で修正するか、 plist というちょっと特殊なXML形式のファイルを編集しないといけないので、ちょっと面倒なのですが、 fastlane を利用することで、自動化されたビルドの中で間違いなく変更することができます。

f:id:suzaku114:20200208142327p:plain

1つ目と2つ目は、 CircleCI 上での利用でしたが、もちろんローカルの環境で利用することもできます。

ここでは、無料版と有料版の2つの ipa ファイルを出力するようなアプリで、両方のバージョン名を一度に更新する例となっています。

パーセントと w でかんたんに配列を作り、それを each で回して、それぞれのファイルを書き換えています。

実行するときには、このようにコマンド引数として渡す形になります。

と、 Ruby の each などを使った例を出したくて書いてみましたが、実際には increment_version_number というアクションがすでに存在していて、それでも同じような動作をさせることができます。
ただ、特定の scheme だけはバージョン名を変えたくない、などのプロジェクトの特殊事情に合わせて、 Ruby のコードで実現する手段がある、というのは良い点かと思います。

f:id:suzaku114:20200208143009p:plain

と、いうことで、 Ruby ができる人は、プロジェクト毎の特殊事情に合わせて、独自のビルドスクリプトを書き、自動化を推進していくことができます。

ただ、 iOS の plist だったり、 scheme の知識は多少なりとも必要になるので、そっちの知識も必要にはなります。

f:id:suzaku114:20200208143651p:plain

続いて、 Danger の例を紹介します。

f:id:suzaku114:20200208143720p:plain

またしても突然ですが、コードレビューをしてて辛さを感じることはありませんか?

インデントのズレとか、変数名の命名規則に則ってないものとか、Pull Requestの説明文のフォーマットが決まっているのにそれを守ってくれないときとか。

そんなときに、レビューである程度指摘したりすると思いますが、
細かい指摘が多いと、指摘する方もされる方も辛かったり、
単純に時間がかかってしまい、本質的なレビューをする時間がとれなくなってしまったり、ということが発生してしまうかと。

f:id:suzaku114:20200208144019p:plain

そんなときに便利なのが、 Danger です。

公式サイトなどでは、こんな英文が書かれていて、ざっくり言うと、機械にできることは機械にチェックさせよう、ということかと思います。

f:id:suzaku114:20200208150820p:plain

もうちょっと具体的なイメージとしては、こんな感じです。

開発者が GitHub 上で Pull Request を作ったことを検知して CI サービスが動作して、
その CI サービス上で Danger が動作します。
Danger の中では ktlint や SwiftLint といった Linter が動き、その結果を Pull Request にコメントしてくれるので、開発者は他の人にレビューしてもらう前にそれを直す、といったフローです。

f:id:suzaku114:20200208151203p:plain

例えば GitHub 上での見た目ですが、コメントには大きく2パターンあります。

まずは、こちらのキャプチャのような、 Pull Request 自体にコメントするパターンです。

f:id:suzaku114:20200208151604p:plain

続いて、 Linter などの結果は主にこちらが使われるのですが、修正した行に対するコメントです。

キャプチャのように、修正した行のすぐ下にコメントが付くので、どこが指摘されているのかが、一目瞭然ですね。

f:id:suzaku114:20200208151718p:plain

ここまで、説明のために GitHub + CircleCI を例にして説明や図を書きましたが、 Danger は他のサービスとも連携できます。

リポジトリとしては、主要なサービスである、GitHub、GitLab、Bitbucketの3つに対応しています。

CIサービスとしてはさらに多くのサービスに対応しており、いろんなところで動かすことができます。

f:id:suzaku114:20200208152142p:plain

もうちょっと Danger の動きをイメージしてもらうために、まずはプリミティブな Danger の設定方法を説明します。

Danger では、 Dangerfile というファイルに、どんなチェックを行うか、結果をどのように通知するかを記述します。
この Dangerfile が、Rubyで記述できます。

使えるメソッドとしては、 warn や fail といった、重要度に応じたメソッドと、
それらに引数として file や line を指定することで、先程の行指定のメッセージを通知することができます。

f:id:suzaku114:20200208152421p:plain

そして、結果を通知する前に、チェックを行う必要があります。

多くの場合、 Pull Request ベースでチェックする際には、どのようなファイルが変更されたのか、 Pull Request の説明文などの属性情報などを見ます。

ここにあるような、各種メソッドで、そういった情報を取得することができます。

f:id:suzaku114:20200208152708p:plain

と、説明してきましたが、実際には、 warn などのメソッドを直接利用するのではなく、用意されている Plugin を利用することの方が多いです。

f:id:suzaku114:20200208152811p:plain

多くの Plugin が公式サイトで紹介されており、スマホアプリ開発でよく使われそうなものをハイライトしてみました。

ちなみに、 checkstyle_format という Plugin は私が作成したものでして、
ドキュメントへの追加依頼を Pull Request として出したら、無事に追加いただけた、というものです。

f:id:suzaku114:20200208153018p:plain

そのコードを例として出していますが、 Plugin 自体は Ruby gem です。

Plugin を継承したクラスを実装して、 Ruby gem として公開しておけば、いろんなプロジェクトで利用することができます。

f:id:suzaku114:20200208153210p:plain

利用する場合には、通常の Gem と同じように、
Gemfile に記述してインストール、 Dangerfile の中で設定や実行を行います。

f:id:suzaku114:20200208153312p:plain

ということで、つまりは、 Ruby ができれば、独自のチェックルールを作ることができます。

f:id:suzaku114:20200208153406p:plain

また、先程出てきたように、 Dangerfile 自体も Ruby で記述します。

ここ上で、 Plugin の設定や実行、 Plugin にするまでもないような細かなチェックを記述したりします。

こちらも、事例を3つ紹介します。

f:id:suzaku114:20200208153719p:plain

1つ目として、 Pull Request の説明文に対するチェックです。

Androidアプリ開発では、多くの場合、 layout の XML が書き換わっているということは、見た目が変更されています。

そんなとき、"実際に見た目はどう変わったのか"を pull して実行する前に分かれば、コードレビューがスムーズかと思います。

f:id:suzaku114:20200208153931p:plain

例えば、これはちょっと違うのですが、デバッグ用のライブラリを追加したときの Pull Request です。

どんな UI が表示されるのか?というのが、コードの差分だけだと分かりづらいのですが、キャプチャを貼っておくことでイメージしやすいと思います。

f:id:suzaku114:20200208154213p:plain

そんなチェック処理ですが、 Ruby が使えるので、そのまま書けます。

変更されたファイルの中に layout フォルダ内の XML があるかを確認し、 Pull Rquest の body に画像が含まれているかを確認します。
その条件に合致しないときに、 Danger の fail メソッドを利用することで、メッセージを通知することができます。

f:id:suzaku114:20200208154439p:plain

2つ目の事例ですが、アプリケーションコードが変更されていたら、対象のテストコードも変更されていてほしいですよね。

そんなときも、こんな感じで素直に書けます。

f:id:suzaku114:20200208154626p:plain

この Dangerfile では fail させてしまっていますが、 warn や message にすることで、強制力を下げることができます。

また、これだとかなり雑なチェックになってしまっていますが、もうちょっと頑張れば、
特定のパッケージの Hoge.kt に変更があれば、対応するテストコード内のパッケージの HogeTest.kt が変わっていること、
といったチェックも可能かと思います。
ここまでできれば、どのファイルに対するテストが変更されていないのか、をメッセージとして通知することもできそうですね。

f:id:suzaku114:20200208155019p:plain

3つ目としては、
CI を実行すると、なんらかの成果物ができることは多いと思います。

例えば、アプリの配布用のURLだったり、テスト結果の html だったりですね。
Pull Request から、それらの成果物へリンクが貼ってあると、レビューする際にも便利ですよね。

f:id:suzaku114:20200208155349p:plain

URL さえ取得できてしまえば、 Danger を使えば、それを通知することはかんたんです。

URL を取得するには、 API のレスポンスから取得したり、環境変数から文字列を生成したりしますが、 Ruby が使えるのでかんたんに書けると思います。

f:id:suzaku114:20200208155517p:plain

ということで、 Ruby ができれば、プロジェクトに合わせたルールを作ったり、自動のコードレビュー環境を整備したりすることができます。

f:id:suzaku114:20200208155602p:plain

まとめです。

Ruby が書ければ、開発環境をより良くすることができます。

fastlane を設定することで、ビルドやデプロイ周りを自動化でき、手作業の手間を減らせます。

Danger を設定することで、機械的なレビューは機械に任せて、人間は本質的なレビューに集中することができます。

f:id:suzaku114:20200208155743p:plain

という感じで、"Rubyができれば..."と言い続けてみましたが、 fastlane や Danger は他の言語の対応も進んでいて、実は Ruby に限った話ではなかったりします。

とはいえ、 Ruby は"書きやすい"言語だと思うので、それぞれでも Ruby が一番多く使われているのでは?と、個人的には感じています。

f:id:suzaku114:20200208160004p:plain

以上、ご清聴ありがとうございました。

おわりに

ということで、発表できなかったスライドを、ブログ化してみました。

これを見て、 fastlane や Danger を使って環境を改善しようと思う人が一人でもいれば良いなーと思います。

(スライド作るのも大変でしたが、記事化するのも結構たいへんですね。。。)