RWCに交通費会社持ちで参加してきた

こんにちは!Crowd Agentのエンジニアが先週行われたRuby World Conference 2017に参加してきました。非常に魅力的なイベントだったので、トークの中から印象に残ったものをピックアップしてご紹介します。

f:id:grooves:20171101103259j:plain
松江では”るびー”と聞くと宝石よりも「コンピュータの何か」を連想する人が多いそうな。

1日目

エンジニアのbary822です。groovesには最近加入して、大阪からフルリモートで働いています。

今回はRWCの1日目で行われたトークの中から、私の印象に残った2つをピックアップしてご紹介します。

Keynote by Matz

Rubyユーザー数推移

Rubyをつくってから、ユーザー数がどのように推移していったのか。というお話でした。

1人(Matz本人)だけから、メーリングリストを公開すると、2,3週間で200人になったそうです。当時は新しいプログラミング言語にユーザーが定着しづらい状況だったらしいので、それを考えるとこの伸び率はMatzの予想を遥かに超えていたそうです。それだけRubyの魅力に気づいた人が当時から多かったことがわかりますね。

また、ML経由で開発に参加する人も徐々に増えてきたそうです。当時はオープンソースという概念も一般的ではなく、顔も知らない人が自分のプロダクトの開発に参加してくれるなど予想外の出来事だったとおっしゃっていました。

Ruby初の英語で書かれた本、Programming Ruby: A Pragmatic Programmer's Guideが発売されると、ユーザー数は10,000人規模まで急速に伸び始めたそう。Dave Thomasが共同執筆者であることから彼とRubyとのつながりはここから始まったのが推測できますね。Rubyは後のRailsの発明のおかげもあり、そこからさらに加速し、現在では全世界で1,000,000人以上のユーザーを持つプログラミング言語へと成長した、というのがRubyのユーザー数の推移を基にした歴史の話でした。

(OSS)コミュニティについて

コミュニティが生き残るには、変化が大きすぎても小さすぎてもダメだというお話です。

例えばソフトウェアで言えば、互換性を保ちつつも新しい機能やパフォーマンスの改善をし続けていく必要がありますよね。

これは個人的な意見なのですが、Rubyコミュニティはこの「互換性」というのものを単なるプログラムの互換性以上のものと捉えていると考えています。それはプログラマの互換性です。Rubyプログラマに「なぜRubyなのか」という質問をした時に必ずと言っていいほど返ってくるのは、「書いていて心地いいから」ということなんですよね。この心地よさこそがRubyの最大の特徴でもあることから、RubyプログラマがRubyらしくプログラムをかけることはある種の「互換性」なんじゃないかなと思います。

Rubyによるたのしいユーザー基盤再構築 by 諸橋 恭介さん

楽しく開発し続けるには

諸橋さんは現在Cookpadでユーザー情報をコアプラットフォームとして提供するための開発プロジェクトに参加していて、彼のチームで「楽しい」開発を実現するために行ったことをお話してくださいました。

具体的には、楽しい開発を考えるための3つのステップとして、

  • コーディングするのが楽しい
  • チームで開発するのが楽しい
  • チームとチーム外の人とサービスリリースするのが楽しい

ということを挙げておられました。

コーディングするのが楽しい

Rubyはそもそも楽しくコードがかけるようにデザインされているのですが、しかし、そんなRubyを持ってしても、アプリケーションのコードが複雑になるにつれ、コーディングをするのが楽しくなくなってしまう、ということはありますよね。

複雑すぎてメンテンナンスが困難となったアプリケーションのメタファーとしてレガシーコードということがよく挙げられますが、我々はこのレガシーコードがお金を生むからこそ楽しくコーディングができる環境があることを認識しなくてはならない。なので、レガシーコードに真摯に向き合い、メンテナンス性を高める努力をすることで、これをまた楽しくコーディングできるようにしようと提案していました。

チームで開発するのが楽しい

ほとんどの開発プロジェクトに置いてはチームで開発することが前提となりますよね。

自分の考える「楽しい」の定義が他のメンバーのそれとは異なるので、チーム単位での「どうすれば楽しいか」という共通認識を持つことが最初のステップだそうです。そこからは振り返り、見積もり、計画づくりを軸としたイテレーションを回していき、どうすればより楽しい開発ができるチームになれるかを追求していくというプロセスがいいのだそう。

また、見える化はチームとしての「楽しい」を追求していく施策の効果的な施策の1つだそう。具体的には、バーダウンチャートでプロジェクトの進捗を見える化することで、プロジェクト完了をゴールとして、いま自分たちがどのステージにいるのかを明確にすることができたそうです。また、イテレーションの振り返りの中でtryとして上がった項目をいつでも意識できる場所に配置することも効果的だったようです。

チーム以外の人とサービスリリースするのが楽しい

チームが変われば「楽しい」の定義が変わる。「楽しい」の定義が変わればそれを基に発展してきたチーム文化も変わる。

自チーム以外のバックグラウンドが異なる人達と一緒に価値を届けることができるというのはそれだけで楽しさが味わえる一方で、その文化の違いから来る困難も多いそうです。その中でも私が一番なるほどと思ったのは、同じものを同じ名前で呼ぶことの重要さでした。

ある概念が抽象化されたものであればあるほど、チーム間でその認識にズレが発生する可能性が高くなる。そのため、それが具体的にどういうものを意味していて、何という名前で呼ばれるかを明確にしておくことは重要だそうです。

新しいメンバーがチームに入った時

これはトークの後で個人的に質問したことです。

新しいメンバーがチームに入った時に、その人が考える「楽しい」とチームが考える「楽しい」にギャップがあった場合にどうすればよいか?という質問に対して、

その人が考える「楽しい」を加味した上で、チームの「楽しい」を再定義する必要がある。変化が起こることは受け入れる。ただし、「楽しい」の定義が全く違うベクトルの人はチームに入れないようにするというのも選択肢として考えてよい。

という回答を頂きました。

自分の中ではチームの「楽しい」の定義はそのチームの文化になるものであり、変化させるべきではない。という考えを持っていたので、それを再定義し続けていくという意見は新鮮に感じました。チームの規模が大きくなるにしたがって、多様な考えを持った人が入ってくるということを考えれば、その方が持続可能なチームの発展が望めるのかもしれないと思いました。

f:id:grooves:20171101172607j:plain
Ruby PrizeはRubyコミュニティに大きく貢献した方に送られる賞。賞金付きのものは今ではこれだけらしい。

f:id:grooves:20171031202722j:plain
鰆を香りのある木の上で栗、まいたけ、そして「むかご」と呼ばれる植物の芽のようなものと一緒に焼いたもの。美味。

2日目

エンジニアの@talkto_meです。二日目を担当します。

Ruby Is Nice so We Are Nice by 角谷 信太郎さん

f:id:grooves:20171102101044j:plain

メディアとしてのRuby

Matzの最近のセッションで、"Matz is nice so we are nice" という表現が "Ruby is nice so we are nice" に変わったことをきっかけとして、Rubyのナイスさがどのように育まれてきたのかという話がありました。 Rubyist(Rubyに対して単なるお客さん以上の気持ちを持っている人)が持ち寄った"いい感じ"の成果が、Rubyのナイスさを育てていると受け止めており、"いい感じ"の一例としては、RubyKaigi 2017 のMatzの基調講演でのmoduleの使われ方の変遷に表れていると感じたとのことでした。

「Rubyをキメると気持ちいい!」というMatzの言葉がありますが、Rubyは書き手にプログラミングの楽しさを感じさせる言語としてデザインされています。書き手の想いや楽しいという気持ちをコードを介して読み手に感じさせることのできるRubyのメディアとしての側面についても言及していました。 最近、弊社では月に一度Railsのコードの歴史を辿っていく勉強会をしているのですが、初期のActiveRecordで登場したmethod missingの大胆なメソッドの呼び出しやhas_finderに始まったnamed scopeのシンプルさは、キメた時の気持ちよさを読み手が感じられる実装だと感じました。

ポエムとしての仕事

以前よりもビジネスとしてのRubyの利用は増えている一方で、仕事を通して"楽しさ"を共感できる職場はそれほど増えてはいないと感じているとのことでした。 ビジネスとしてのソフトウェア開発は、インターネットの成長とともに自然と発展した"野生のソフトウェア"であるRubyとは異なり、人工的な環境であるため"いい感じ"を再現させる必要があると考え、Rubyと同じメディアとしてアジャイル/リーンを通して、仕事の送り手の"楽しい"を受け手の心に再現できないかとおっしゃっていました。

QAで角谷さんがさりげなく発した「うまくいかなくてもいいです、また別のやり方探しましょう」という一言が、アジャイル/リーンをメディアとした"いい感じ"を再現するために必要な考えなのではないかと感じました。

f:id:grooves:20171102141439j:plain

Rubyプログラマが育つ仕組み−Rubyでの受託開発を10年回してみて by 大場寧子さん

有志による新入社員研修改善プロジェクト

実務でのOJTベースの研修は、新入社員と受け入れ側の両方で非効率と感じるシチュエーションが見受けられていました。 株式会社万葉ではホラクラシーな組織形態を採用しており、担当者が自律的に判断する環境を整えているそうです。現状の問題を解消するために有志による改善プロジェクトが発足したとのことでした。 新しい研修では、習得してほしいスキルをベースに24のステップになっている擬似プロジェクトを採用しており、要件をあえて緩くすることで、状況をより現実に近づけ、自分で仕様を検討して決める判断力やコミュニケーション能力を養うことができます設計になっているとのことです。

研修を軸に社員同士のコミュニケーションが活発になる

研修を画一化すると、メンター以外の社員も自然とレビューに参加する動きが見られるようになったそうです。変化するベストプラクティスやコーディングパターンの議論も活発になり新入社員以外でも知見を得られる良い機会になったとのことでした。

初めての人がチームに新メンバー入る時、スキルに応じた仕事の選択や文化的な擦り合わせには多少なりとも時間がかかります。開発をスピードアップさせるために必要なコストですが、一時的にチームに不安な状態が生まれるため、事前に解消・軽減することができる研修方法には魅力を感じました。研修を繰り返すことで、レビューする側の社員の負担も軽減されていき、チームを超えた横断的なコミュニケーションを生み出している点も複数チームの交流を考えている企業にはもってこいだと思います。

研修期間完了は人により異なり、その分のコストが発生する一方で、新入社員の得手不得手の共有、文化のすり合わせが行われ、実案件へアサイン後はスムーズに活躍できるようになったそうです。プロジェクトで育ったメンバーがメンターとなり研修内容が改善していく流れもエンジニアが会社を育てていく良い文だと感じました。

なお、 https://github.com/everyleaf/el-training に擬似プロジェクトの成果が公開されています。弊社でもエンジニアの教育の機会にはぜひ参考にしたいと思いました。

f:id:grooves:20171101181250j:plain f:id:grooves:20171102172336j:plain

エンジニア募集

株式会社groovesでは、エンジニアを採用しています。 私たちと働くことに興味ある方、気軽にご連絡ください。

jobs.forkwell.com

jobs.forkwell.com

開発合宿に島根県松江市がおすすめな理由

f:id:grooves:20171030193642j:plain

こんにちは、grooves の赤川です。 11/1、2 と島根県松江市にて RubyWorld Conference 2017 が開催されましたね。 実は株式会社groovesではエンジニアメンバーが一足早く現地に乗り込み、開発合宿を実施していました。

海と、山と、カニがおりなす秀麗無比なる島根の地に、メンバーの士気も終始高まりっぱなし。 皆さんにもぜひおすすめさせてください。

おすすめの理由その1 ー 非日常な空間

国の登録有形文化財であり、110年の歴史をもつ美保館を、一棟まるごと貸し切ることができました。 海を眺めながらのコーディング、畳に寝っ転がりながらのペアプロ、など、日常からの解放感を感じながら開発に集中することができます。

中央の大きな建物が旅館、左隣の黒い屋根の建物が今回の合宿所 美保館 f:id:grooves:20171031125735j:plain

中はまるで千と千尋の神隠しの舞台 f:id:grooves:20171031113012j:plain

f:id:grooves:20171031113437j:plain

とにかく広い合宿所 f:id:grooves:20171030134930j:plain

海を見ながらコーディング f:id:grooves:20171030151247j:plain

f:id:grooves:20171031095040j:plain

畳の上でペアプロ f:id:grooves:20171031094954j:plain

おすすめの理由その2 ー 開発意欲を妨げない設備

  • Wi-Fi完備
    • 合宿所の中は全てWi-Fiが飛んでおり、好きな場所で好きなように開発することができます(ただしたまに重くなるので個人でもネットにつなげる準備があると安心です)
  • 24時間利用できる合宿所
    • 合宿所は24時間利用することができ、深夜にコードが乗ってくるエンジニアの気持ちを止めません。ちなみに大浴場も24時間入ることが出来るので、いつでもリフレッシュが可能です。
  • トイレがきれい
    • 110年前の建物というとトイレや浴場が古いイメージがありますが、水回りはリフォームされかなりきれいになっていました。合宿中は何度も利用することになるので清潔さは意外と重要です。

おすすめの理由その3 ー 島根県松江市職員によるおもてなし

その3にして、最大の理由です。 今回の合宿企画、最初から最後まで松江市職員の方が徹底的にサポートしてくれました。

会社での合宿企画というのは、実は非常に手間のかかる作業なのですが、その大部分をご支援いただき、また、抜け漏れやすいポイントをご指摘していただけるので、スムーズに企画することができました。この安心感は、他のエリアでは絶対に味わえないでしょう。

具体的にご支援頂いたこととして、

  • 参加人数・予算に合わせた合宿所の選定と予約の手配
  • ホワイトボード、プロジェクター、電源タップなどの備品のご用意
  • 観光プランのご提案
  • なにより、あたたかな笑顔

などがありました。

ちなみに、今回groovesの開発合宿を担当していただいた福田さんは、ITリテラシーがめちゃくちゃ高く、Facebookメッセンジャー や appear.in などでスピード感を持って情報交換することができました。 失礼ながら勝手に抱いていた地方公務員のイメージ像が覆りました。

福田さん、この場を借りてお礼申し上げます。

もし島根県での開発合宿にご興味を持った方がいらっしゃいましたら、ぜひ福田さん(Mail:richi [at] city.matsue.lg.jp )にご連絡してみてください。

まとめ

島根県松江市、最高です。おすすめします。

エンジニア募集

株式会社groovesでは、エンジニアを採用しています。 私たちと同じチームでユーザーへの価値提供にこだわりたい方、ぜひご連絡ください。

jobs.forkwell.com

jobs.forkwell.com

おまけ

開発合宿の模様を写真で紹介します。

普段リモート中心で、オフラインで交流する機会の少ない Crowd Agent チーム。 この合宿を機に、もう一度チームビルディングに取り組みました。 f:id:grooves:20171030141312j:plain

f:id:grooves:20171030141624j:plain

休憩時間には、すぐ隣の美保神社へ参拝 f:id:grooves:20171030152900j:plain

f:id:grooves:20171030152837j:plain

f:id:grooves:20171030153022j:plain

歴史ある美保神社で ITエンジニアの活躍を祈りました f:id:grooves:20171030153049j:plain

だんだんは、ありがとう、という意味らしい f:id:grooves:20171031125350j:plain

海と山を眺めながら息抜き f:id:grooves:20171030155624j:plain

休憩を終えて再開 f:id:grooves:20171030151707j:plain

国内唯一の Ruby / Railsコミッターであり、grooves の取締役を務める松田明(@a_matsuda)氏も参加 f:id:grooves:20171030141225j:plain

f:id:grooves:20171031115108j:plain

夜はSwitchのゲーム、ヒューマンリソースマシンを使ってモブプログラミング f:id:grooves:20171030223350j:plain

大正ロマンあふれる合宿所 f:id:grooves:20171030141651j:plain

朝昼晩、料理には全て刺し身が f:id:grooves:20171031120430j:plain

イカを狙う猫 f:id:grooves:20171031124714j:plain

海の反対側 f:id:grooves:20171031090008j:plain

f:id:grooves:20171031125231j:plain

海の青、空の青 f:id:grooves:20171031125756j:plain

旅館の前で f:id:grooves:20171031224119j:plain

最後まで写真をご覧になった方へ

私たちと働きませんか?興味ある方は気軽にご連絡ください。

jobs.forkwell.com

jobs.forkwell.com

Forkwell のソースコードの複雑度(AbcSize)を計測してみた

Forkwell Portfolio の新しい機能を開発しながら、リファクタリングしている日々の @sinsoku です。 今日はリファクタリングの改善結果が気になったので調べてみました。

残念ながら簡単な方法は見つからなかったので、「メンドイ」という気持ちに負けずにスクリプトを書きました。

AbcSize とは

  • Assignment: 変数の代入
  • Branch: 関数の呼び出し
  • Condition: 条件分岐

から計測する複雑度です。Ruby だと RuboCop で簡単にチェックできます。

計測スクリプト

RuboCop 単体では AbcSize の数値を出力できないため、簡単なスクリプトを書きました。

ファイル 概要
calc_abcsize.rb AbcSize を計測し、tmp/abcsize.csv を出力する
trace_abcsize.rb 2014/1 から月初のコミットを checkout して AbcSize を計測する

雑な実装のスクリプトですが、 gist で公開してるので参考にどうぞ。

https://gist.github.com/sinsoku/2c37b2efed514c7ac212203dc867e045

実行方法

下記のコマンドで 2014〜2017年の AbcSize の集計が出来ます。

$ curl -L -O https://gist.github.com/sinsoku/2c37b2efed514c7ac212203dc867e045/raw/ef0afa616b23fe6c976f37a6a154a92e86f215ac/calc_abcsize.rb
$ curl -L -O https://gist.github.com/sinsoku/2c37b2efed514c7ac212203dc867e045/raw/ef0afa616b23fe6c976f37a6a154a92e86f215ac/trace_abcsize.rb
$ ruby trace_abcsize.rb
$ echo 'date,20..29,30..39,40..49,50..59,60..69,70..79,80..89,90..99,100..' >> result.csv
$ for f in $(ls 20*.csv); do echo ${f%.csv},$(tail -1 ${f}) >> result.csv; done

グラフ

生成された result.csv を Google スプレッドシートでグラフ化したのが下記の2つです。

f:id:sinsoku:20170713165255p:plain

f:id:sinsoku:20170713165305p:plain

感想

  • ときどき AbcSize の高いコードが混入している
  • ただ、増え続けてはいなくて、ちゃんと減っている
  • AbcSize 30 以上のメソッド数は着実に減っている

グラフで見ても、リファクタリングで複雑なコードが少しずつ減っているのが分かりました。

まとめ

コードの複雑度は目に見えないので、こうやってグラフにすると面白いですね。 皆さんも自社のプロダクトの AbcSize を計測してみると新しい発見があると思いますので、ぜひお試し下さい。

そして、個人的に各社の AbcSize がどのくらいの数値なのか気になるので、可能なら技術ブログでの公開をご検討ください。 各社の AbcSize が公開されるのを楽しみにしてます :-)

Forkwell のポートフォリオ機能をリニューアルしました

こんにちは、Forkwell 開発チームの @sinsoku です。

先日 Forkwell のポートフォリオ機能を Forkwell Portfolio としてリニューアルしました。

f:id:sinsoku:20170612092551p:plain

リニューアルの大きな変更点は下記の通りです。

  1. リポジトリの解析
  2. ポートフォリオの自動更新
  3. 友達からフォロー/フォロワーに変更
  4. デザインの一新

リポジトリの解析

登録されたリポジトリのコミットログを解析し、ユーザーが普段書いているプログラミング言語やコード変更量などをグラフで表示します。

f:id:sinsoku:20170612092708p:plain

デフォルトでは公開リポジトリのみですが、プライベートリポジトリの API アクセスを許可すれば、仕事で書いているコード変更量もグラフに反映させることができます。

バッジ

リポジトリを登録すると、よく書いているプログラミング言語のバッジを取得できます。

f:id:sinsoku:20170612092721p:plain

この画像のようなバッジだと「Ruby, JS をメインで触っていて、 Elixir, Haskell は少し触って飽きた人」というのがバレます。

実装の話

解析処理は AWS Lambda 上で git log --date=iso --stat のコマンドを実行し、そのログを s3 に送って、s3 の通知を受けてアプリが DB に保存するような実装になっています。

f:id:sinsoku:20170612092733p:plain

Forkwell が保持しているのはログだけで、 コードの中身は保存していません*1

ポートフォリオの自動更新

f:id:sinsoku:20170612092747p:plain

RSS フィードを登録しておけば、定期的に自動で記事・スライドをインポートすることができるようになりました。

友達からフォロー/フォロワーに変更

f:id:sinsoku:20170612092800p:plain

リニューアル前は Facebook の友達データをそのまま参照しており、Twitter や GitHub でアカウントを作成したユーザーは友達 0 人と悲しいことになっていました。リニューアル後は Forkwell 上でフォローできるようになりました。

デザインの一新

デザインが一新され、 Forkwell のスタイルガイド を使うように変更しました。これにより jQuery を多用していた JavaScript が消え、 React.js を使うコードに置き換わりました。

ぜひリニューアルした Forkwell Portfolio にあなたのアウトプットを登録して、自分のスキルを可視化してみてください。

また、何か気づいた点などあれば 公式Twitter にフィードバック頂けると幸いです。

*1:プライベートリポジトリのコードをDBに保存するとか怖くて無理です

Slackのemojiをデカくする

こんにちは。デザイングループのミヤギ(twitter)です。

唐突ですが、先週めでたく最終回を迎えた『けものフレンズ』というアニメはご存知でしょうか。

上記の様なブログも書かれていて、かなり流行っていましたね。
僕自身もハマってしまい、11話〜最終回のアツい展開に深夜に1人で涙してしまいました。

f:id:ringo_girl:20170404120819p:plain

けものフレンズの emoji を使いたい

弊社では社内でのチャットに Slack を使っているのですが、Slackには独自のemojiを登録できる機能があります。今さら最終回を迎えたアニメの話で恐縮ですが、『けものフレンズ』の emoji を登録したくなり、素材を探していたところ以下のようなものが見つかりました。

けものフレンズアイコンまとめ【フリーアイコン】

@Kiguchi1902さんありがとうございます。

emoji が小さい

emoji を登録はしたものの、実際に使ってみるとサイズの問題でセリフが小さく、「すごーい!」という感情を上手く表現できないというもどかしさがありました。

f:id:ringo_girl:20170404120832p:plain

Slack の custom emoji は最大 128x128 でアップロードできますが、Developer Toolsで覗いてみると、サイズが縮められているようだったので、どうにか元の画像を表示できる方法を探していたところ、APIで画像のURLを取得できることがわかりました。

f:id:ringo_girl:20170404120841p:plain

Slack API | emoji.list method

このURLを attachments に設定することができれば、emojiをデカくするということが可能では、と思い実装をはじめました。

emoji をデカくする

実際に作ったものはGitHubに置いています。

Slash commandsを使う

Slash Commandsを使って以下のコマンドを発行することで、emojiを大きくするようにしました

/stamp :custom_emoji:

Slash commandsを入力すると、Outgoing Webhooksの要領で、 コマンド(/stamp)テキスト(:custom_emoji:) を受け取ることができます。それらを受け取った後で、emoji.list から該当する custom_emoji のURLを取得し、attachmentsに画像を埋め込んでメッセージを返すようにしています。

ユーザーの認証を行う

Slash Commandsだけでは不十分で、Private GroupやDirect Messagesではデカい emoji を投稿できる権限が無いので、ユーザー毎に認証してtokenを保存するようにしています。

SlackでAppを作り適切なScopeを与えて、チームにインストールしています。

たーのしー!

f:id:ringo_girl:20170404120906g:plain

これで custom emoji をデカくする機能の実装が完了しました。すごいことがあったら「すごーい!」と感情が表現できるようになりました!

その他のcustom emojiも使える

emoji.listというAPIを使っているので、custom emojiであれば全て元サイズで表示することができます。

f:id:ringo_girl:20170404120929g:plain

気をつけていること

この機能でデカいemojiが氾濫すると、本来のコミュニケーションが取れなくなりチーム内でストレスが溜まってしまう可能性もあるので、用法用量を守るようにしています。
弊社内のSlackではたまに使用される程度で、支障が出るほどではありませんでした。

まとめ

『けものフレンズ』のアイコンを使いたいという思いがことの始まりだったのですが、custom emoji全てを扱うことができるので、Slackでのコミュニケーションが賑やかになりました。

また、今回はじめて hapi という Node.js のWebフレームワークを使ったのですが、hapijs/joi というバリデーションのライブラリや認証周りがプラグインとして準備されていて便利でした。

デザイナー採用

株式会社groovesではデザインとフロントエンドがやりたいフレンズを募集中です!よろしくねー!

jobs.forkwell.com

www.wantedly.com

www.moreworks.jp

GitHubリポジトリが突然消えたときにやるべきこと

新年あけましておめでとうございます。ことよろ。
最近 Forkwell のポートフォリオ機能を弄っている@sinsoku です。

今日は弊社で起きた「リポジトリが突然消えた事件」について書きたいと思います。

事の始まり

昨年末の26日の朝、 fork したけど使っていないリポジトリがあったので、何気なく削除しました。 その30分後、同僚のapp2641に声をかけられました。

app2641:「なぜか(メイン)リポジトリが404なんですが、sinsoku さん何か知ってます?」
sinsoku:「え、いや、分からないです。私の方でも調べてみます。(もしかして...)」

自分でもリポジトリのページを表示してみました。

f:id:sinsoku:20170118110130p:plain

404 ですね。マジか...。Audit log を確認してみるか。

f:id:sinsoku:20170118110145p:plain

見覚えあるアイコンの横に repo.destroy て書いてあるじゃないか...o..rz

GitHub のサポートへ連絡

下記の内容で問合せました。

Hi, GitHub Team.

I accidentally deleted a "grooves/xxx" repository. Can you resurrect it?

その後、サポートの人から返ってきた返信を要約すると下記の通り。

  • GitHub ではリポジトリを復元できるようにアーカイブに保存している
  • grooves/xxx のリポジトリは検索したけど、アーカイブに存在しない
  • sinsoku/xxx のリポジトリはあるけど、これ?

GitHub では削除した後に問い合わせれば復元できるっぽいですね。 通常なら

I can't see a "grooves/xxx" repo.

https://github.com/grooves/xxx

And Audit log shows "repo.destroy".

と送ったところ、「技術的な問題があって復元できなかった。エンジニアチームに尋ねた」と返ってきた。

(´-`).。oO(もしかして GitHub のバグを踏んでしまいリポジトリが死んだのでは...)

そして新年

年末年始で返信もなく GitHub も休んでそうだったので、連休明けの 1/11(水) に進捗を確認してみた。

Could you tell us about the current status?
The repository is not restored yet. How long will it take?

翌日1/12(木)の夜には返信があって、無事にリポジトリが復活した。

Sorry for the delay on this one but the repository should now be restored.

リポジトリが無い期間の開発

初日

すぐ復活するだろうと思っていたのと小さい変更だったので、2つだけ Slack上で diff をレビュー してデプロイしました。

f:id:sinsoku:20170118110210p:plain

「手順書を用意 => バックアップ作成 => パッチ適用 => ホットデプロイ」を手動でやるとか、旧世代のデプロイに懐かしさを感じた1日。

2日目以降

リポジトリの復元に時間かかりそうな返信内容だったのと、さすがに 2017年にもなって手動デプロイとか無理 なので、一時リポジトリを作成して作業することになりました。

  • 一時リポジトリの作成
  • CI の環境構築
  • Capistrano の設定変更

こういうとき Git だとリポジトリの複製が楽で良いですね。

リポジトリが復活した後

Capistrano の設定を戻し、一時リポジトリの Pull Request, Review Comment はスクリプトを書いてバックアップを保存しました。

#!/usr/bin/env ruby
# frozen_string_literal: true
require 'fileutils'
require 'octokit'

OWNER = 'grooves'
REPO = 'tmp_repo'
FULL_NAME = "#{OWNER}/#{REPO}"
DOC_PATH = File.expand_path('../../doc', __FILE__)
PULLS_PATH = "#{DOC_PATH}/#{REPO}/pulls"
COMMENTS_PATH = "#{DOC_PATH}/#{REPO}/review_comments"

Octokit.auto_paginate = true

class RepoBackup
  attr_reader :token

  def initialize
    @token = ENV['TOKEN']
  end

  def save_pulls
    mkdir_p(PULLS_PATH)

    pulls = client.pulls(FULL_NAME, state: :all)
    pulls.each do |pull|
      write_json("#{PULLS_PATH}/#{pull[:number]}", pull)
      puts "saved pulls##{pull[:number]}"
    end
  end

  def save_comments
    mkdir_p(COMMENTS_PATH)

    comments = client.reviews_comments(FULL_NAME)
    comments.each do |comment|
      write_json("#{COMMENTS_PATH}/#{comment[:id]}", comment)
      puts "saved review_comment##{comment[:id]}"
    end
  end

  private

  def client
    @client ||= Octokit::Client.new(access_token: token)
  end

  def mkdir_p(path)
    FileUtils.mkdir_p(path) unless FileTest.exist?(path)
  end

  def write_json(path, obj)
    File.write(path, JSON.pretty_generate(obj.to_h))
  end
end

backup = RepoBackup.new
if backup.token
  puts 'Start backup script'

  backup.save_pulls
  backup.save_comments

  puts "Backup finished and saved to #{DOC_PATH}."
else
  puts 'USAGE: TOKEN=xxx ./script/backup_forkwell_tmp'
end

対策方法

通常なら GitHub に問い合わせれば復元できるっぽいので、厳重な対策はしなくて良いかもしれません。 ただ、公表されているサポートって訳でも無いですし、数時間でもリポジトリが消えたら困るってケースもあると思うので、いくつか方法を挙げておきます。

1. 削除時の確認

今回の件で初めて知ったのですが、リポジトリを削除するときの確認画面でリポジトリ名だけでなく ユーザー名 も入力することが可能です。

f:id:sinsoku:20170118110233p:plain

削除時は sinsoku/xxx のようにユーザー名(もしくは Organization 名)を含めて入力し、念のためスクリーンショットを保存しておくのが良さそうです。

2. 開発者に Admin 権限をつけない

Terraform の GitHub provider を使えば、Organization のリポジトリをコードで管理することが可能です。

  1. Admin を1人だけ作成する
  2. リポジトリを削除するときは Pull Request でレビューしてからマージする
  3. マージ後 Admin の token を使って terraform apply でリポジトリを削除する

上記のような運用を行うことで、より安全なリポジトリ管理ができるかと思います。

3. 外部サービス

f:id:sinsoku:20170118110246p:plain

BackHub という GitHub のリポジトリを定期的にバックアップしてくれるサービスを見つけました。 使ったことがないので詳細は不明ですが Issue, Pull Request などを定期的に保存するなら便利そうです。

まとめ

GitHub のバグなのか、私の操作ミスなのか最終的な原因は分かりませんでしたが、リポジトリが無事に復旧して良かったです。

この記事が皆様の 参考にならない事 を祈っていますが、もしリポジトリが消えてしまった時は本記事を参考にして頑張ってください。

f:id:sinsoku:20170118110254p:plain

Forkwell Jobs の求人編集画面で textlint の文章チェックができるようになりました

もう師走ですね。お疲れ様です @sinsoku です。

本日、 Forkwell Jobs で求人票の文章チェック機能をリリースしました。
求人票を作成・編集する人事様向けの機能です。

文章チェック機能

求人の編集画面で「文章チェック」のタブをクリックすることで、求人票の文章をチェックできるようになりました。

f:id:sinsoku:20161209110800g:plain

チェックしているルール

Forkwell Jobs で採用しているルールは現状だと下記の通りです。

今後の予定

今後もルールを追加・調整して、求人作成がもっと楽になるようにしていきたいと思っています。

この機能が Forkwell Jobs を利用している人事様の助けになれば幸いです。