こちらはドリコム Advent Calendar 2019 における20日目の記事です。
前回は Egliss さんの C++でもGetComponentがしたい! です。


あいさつ

メリークリスマス、じぬです。

本日は何事もなければ忘年会の予定です。
何事かがあって忘年会はなくなったのですが、さらに何事かがあって忘年会が企画されました。

本記事では、最近進めているマップデータの作成を気づいたら自動化していた話をします。

はじめに

DRIP 部

自分は DRIP 部AROW というプロダクトのリードエンジニアをしています。
DRIP 部については他のメンバーが紹介していますので、ぜひぜひそちらをご覧ください。

AROW

AROW は開発者が「3D リアルマップゲーム」を手軽に開発できるようサポートするためのプラットフォームです。
現在は次のようなコンテンツを提供しています。

  • リアルマップのデータ(建物、道、地形)
  • 上記データを Unity で扱うための SDK

ここで挙げているリアルマップのデータを作成するのが、本日の主題です。

本日の三行まとめ

  • 差し込みが多いと本当にはかどらない
  • 自動化は再開機能と終了通知が大事
  • 自動化はやめられないとまらない

経緯

AROW では、OpenStreetMap などの公開されたデータを元に独自のマップデータ(arowmap)を作成しています。
今年の11月、既存の arowmap に対して新たにデータ追加を行う必要がありました。
現在 AROW が配信しているのは日本のマップデータですが、数としては100万ファイル以上存在します。
それらを関東や東北などの地域ごとに分け、順次データ追加を行っていきます。

具体的な内容は次の通りです。

  1. 新しいデータを扱いやすい形に加工する
  2. 既存の arowmap に新しいデータを取り込む
  3. 重複などの不要なデータを削除する

それぞれの処理を行うスクリプトを実装し、あとはデータを用意して実行を繰り返すだけとなりました。

暗雲

今回の作業は、データ量や処理時間の都合で地域ごとに実行を分ける必要がありました。
数回ほどの実行だったため、気づいたときに手動で実行していけばいいだろうと、この時はそう考えていました。。。

このスクリプトを実行しつつ別作業を進めるようになって2, 3日が経つと、朝会などを通して思いのほか作業が捗っていないことが分かりました。
作業を見直してみると、スクリプト実行が思いのほか弊害になっていることに気がつきます。

一番良くなかったのは、処理の終了を検知する用意が無かった点です。
そのため定期的にスクリプトの進行状態を確認しなければならず、別作業の中断が多く発生しました。
地域によってかかる時間にばらつきがあり、終了時間が予想できなかった点も良くなかったのでしょう。

自分たちの仕事は問題解決の手法や仕様、設計など考える作業が多いです。
そのため、心理学で言うフロー状態(極めて高い集中を伴い、作業に没頭している状態)を目指す必要があります。
その点で見ると、作業中どこかでスクリプト実行を意識してしまう今回の方は非常にまずかったものと言えます。

対応

理想の状態は「終わるまで放置できる」「問題があっても簡単にやり直しできる」ということです。
時間を有効活用するため、週末に一連の処理をまとめて実行することもやりたいことの一つでした。
とは言え大がかりにしたくはなかったので、とりあえず動くをモットーに自動化を考えました。

まず、Ruby で次のようなスクリプトを書いてみました。(一部省略しています)

# CMDS 内のコマンドを指定されたインデックスの範囲だけ実行する
# 例: 3 4 と指定されたら 3と4 を実行する
CMDS = [
    # 0
    "puts 0",
    # 1
    "puts 1",
    # 2
    "puts 2",
]
def main(inputs)
    from = 0
    to = CMDS.length - 1
    if inputs.length == 2
        from = inputs[0].to_i
        to = inputs[1].to_i
    elsif inputs.length != 0
        raise "Args Count Error"
        exit
    end
    puts "from #{from} to #{to}"
    CMDS.each_index do |i|
        next if i < from
        break if (to + 1) <= i
        run_cmd CMDS[i]
    end
end
def run_cmd(cmd)
    puts cmd
    system cmd
end
main ARGV

要は、設定したコマンドをターミナルで順番に実行するだけのものです。
実行の際は、何番から何番まで実行するか、ということを引数で指定して実行できます。
メリットは二つあります。

  • 範囲指定でまとめて実行できる
  • 途中でコケてもそこから再開できる

また、スクリプトの終了時にはチャットワークで通知が来るようにしました。
これにより、通知が来るまで気にせず作業に集中できます。

※ bot との微笑ましいやりとり

これで、自分が求めた要件は満たされました。
心置きなく別作業を進められます。

自動化という魔性

これで心穏やかな日々が過ごせると思っていました。
ところが大きな作業を放置できるようになると、それほどでもなかった細かい部分が気になってきます。

  • マップデータを実行マシンに用意するのめんどくさい
  • マップデータの zip 展開、終了時の zip 圧縮めんどくさい
  • 地域ごとにフォルダ名変えるのめんどくさい
  • たまに処理を見ても進捗が分からないのつらい
  • どれくらい時間かかったのかも知っておきたい

Google Drive と連携

マップデータの保存は Google Drive を使っていました。
なので、skicka というライブラリを使えばコマンドラインで操作ができます。

skicka download #{Google Drive のパス} #{ダウンロード先のパス}

zip 展開

シェルを工夫すれば、ワンライナーで zip 展開ができます。

find #{zip があるフォルダ}/ -type f | grep zip | xargs -I{} unzip -d #{展開先のフォルダ} {}

フォルダ名などの一括変更

各処理における入力と出力を整理し、フォルダ名を見直しました。
ルールベースになっていれば、Ruby 内で変数一つを書き換えるだけで事足ります。

進捗の把握

各処理ごとに、生成物を別々のフォルダへ出力するようにしました。
そうすれば入力時はフォルダ内を全て読み込むだけで済みますし、そのフォルダの生成物を見ればどこまで処理が進んでいるかを確認できます。

所要時間の把握

コマンド実行時にローカルファイルに現時刻を書き出すようにしました。
おおよその時間が分かっていれば、今後定期的に実行する際のスケジュールを立てることも容易です。

気づいたら

なんと言うことでしょう。
簡単な自動化で済ませるはずだったのに、気がつくと上記の修正もすべてスクリプトに組み込まれていました。
追加するマップデータの用意から生成物の Google Drive アップロード、使い終わったファイルの削除まで、すべてが一つのコマンドで実行できるようになってしまいました。

おわりに

ふりかえり

今回の件から得るべき教訓は、簡単な作業でも自動化をサボれば想像以上のツケが返る、でしょうか。
朝会など、進捗が良くないことをきちんと検知できる場があったのは幸いです。
自動化については弊社の onda さんも記事を書いていますので、ぜひご一読ください。

作業自動化のすすめ 〜人間がするべきでない作業を減らしたい話〜

欲を言えば、各処理の内部でも進捗の可視化や再開機能があればもっと便利になったと思います。
今回は時間の都合上そこまで手を出しませんでしたが、今後の開発、特にツール開発時にはその点を意識できればと思っています。

まとめ

自動化というのは恐ろしいもので、一つ直すとあれもこれもが気になってきます。
今回は有益だと判断したので対応しましたが、とは言え皆さんにも様々なタスクがあるはずです。
闇雲に自動化にこだわるのではなく、重要なタスクを見極め、その実現に必要であれば徹底して自動化する、そう意識することが重要であるという自戒を込めて本記事を終わりたいと思います。
ご覧いただきありがとうございました。

次回予告

次回は homma suzuka さんのファインアート出の人間が UI を学んだ感想的な学び的なものです。

このあとはお決まりのやつが入ります。せーのっ。
ドリコムでは一緒に働くメンバーを募集しています!募集一覧はコチラを御覧ください!