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をデカくする

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

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

上記の様なブログも書かれていて、かなり流行っていましたね。
僕自身もハマってしまい、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 を利用している人事様の助けになれば幸いです。

Forkwell Scout のつくりかた 〜デザイナー視点〜

はじめまして、デザイナーの@711fumiです。

先日「Forkwell Scout」というスカウトサービスが爆誕いたしました。 (と言っても現在β版です)

f:id:blog_711fumi:20161110130641p:plain

ソフトウェアエンジニアがイキイキと働ける環境に出会えるよう、私達が運営するWebエンジニア向けの転職サイト「Forkwell Jobs」内の新機能としてリリースしたサービスです。 スパム(マッチしないスカウト)のない、エンジニアが正しく評価してもらえるサービスを目指して絶賛開発中です。

今年の春にプロジェクトが動き始め、現在β版までこぎつけることができました。 せっかくなので?デザイナーがどのようにプロジェクトに関わっていたかぼんやり振り返ってみようと思います。

企画段階

企画段階ではプロダクトオーナーを中心に、サービスが目指す方向性を固めていました。 そしてその方向性を元に本当に必要な機能(最低限必要な機能)を洗い出し、イメージを作っていく段階で具体的なデザインタスクが発生しました。

エンジニアや他のメンバーと相談しながら、画面遷移や導線などを確認をおこないました。

デザイン作成とレビュー

必要な機能がある程度固まったら、Sketchでデザインを作成しInVisionなどでレビューを行いました。 InVisionを使うことで、

  • レビュー内容(対応済みかどうか)が残る
  • レビュー会議みたいなのを開く必要がない

ってのはありがたいですね。

(InVisionで思い出しましたがCraftのPrototype機能はいつお目見えするんでしょうね…?)

動きのイメージ、導線の確認

今回はプロトタイピングツールのFlintoをつかって動きの確認をおこないました。 初めて使ってみたのですが、実際に動かせるものを用意して確認することで気がつく問題点や改善点があり、なかなか勉強になりました。 Sketchとの連携も簡単ですしね。 ただプロトタイプを作るのが目的(設計)ではないので、使い所を見極めないとなぁとは思います。

Sketchでのデザインやプロトタイプ作成は実装では無いので、何をどこまで設計(決定)する必要があるのかをデザイナーは最初に確認しておく必要がありそうです。

初期開発

必要となる機能・画面の設計が固まってきたらいよいよ開発です。 スモールスタートを目指すということで、「最低限必要な機能を最速で作る」意識で開発チームは動いていました。

エンジニアとの協業

URL設計などはエンジニアメンバーがやってくれているので、必要なページ(RailsでいうViewファイル)を用意してもらい、デザイナーがそこにガリガリコーディングしていくというスタイルで進めていきました。

「デザインだけ作っておいたからデータ取ってくるとこ実装よろしく」
「とりあえずデータが表示されてるだけのページ作ったんで、見た目はお願い」

というように得意な部分だけやって後は相手にガンガン投げるという方法で問題なく噛み合い、(おそらく)スムーズに初期開発が進んでいきました。

このエンジニア:デザイナーの境界みたいなものはメンバーのスキルセット(及び嗜好性)で決まるとおもうので、チームごとにいいやり方が見つかるよう調整していくのが良さそうです。

素早く形にする

「最低限必要な機能を最速で作る」という方針で進める上で助かったのは、Forkwll Jobsにはスタイルガイドがあるということです \(;∀;)/

CSSスタイルガイドを作って良かった話

トーンが統一された必要なコンポーネントがスタイルガイドで用意されているため、ある程度見た目を保証しつつ、素早くUI実装を進めることができました。

スタイルガイドと一口に言ってもwikiのようなものからコンポーネントを実装してまとめたものまで様々あると思いますが、デザインで迷う部分を少しでも減らすために何かしら準備しておくのをおすすめします。

こっそりリリース〜限定公開

最低限の機能が実装できた後、一部の人のみ利用できるようこっそりリリースがおこなわれました。 ここからはひたすら改善を進める日々です。

ユーザーテスト

開発チームに産技大で人間中心デザインを学んできたエンジニアがいるので、 彼主導で繰り返しユーザーテストを行い、貰ったフィードバックを参考に改修を行っています。

  • 社内チームメンバー
  • エンジニア採用を行っている企業の採用担当者
  • エンジニア

にテストをお願いしました。

実際のユーザー(ターゲットとなる方々)からリアルな意見をもらえることで、いろいろな気づきを得ることができました。 やっぱりそうなのね…と改めて実感させられる事もあれば、想定してたんとぜんぜん違う…みたいな使ってもらって初めて分かることなど様々でしたね。

ただ何よりも、自信を持って仕様の変更や機能の改修をおこなうことができるのが大きいです。 もちろんユーザーの意見をただサービスに反映させればいいというわけではないですし、優先度や大きさみたいなものも見極めなければならないのですが。

そして公開へ…

で、現在はβ版ではありますが全ての方に公開している状態になっています。

引き続きエンジニアのことを一番に考え、エンジニアが幸せになるためのサービスを目指して開発していきますので注目していただければ幸いですー

なんかデザインの話でもなんでも無くなっちゃいましたが… サービスについてご意見ありましたらぜひ教えてください! (ΦωΦ)/

Forkwell の開発で使っている rubocop の設定を公開しました

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

Forkwell の開発では RuboCop を使っていますが、その設定を onk/onkcopesminc/deka_eiwakun を参考に gem にして公開してみました。

github.com

コーディングスタイルについて

forkwell_cop というか、 Forkwell のコーディングスタイルは作成中です。 まだチーム内で議論していない項目は config/todo.yml に記載してあり、これから少しずつ対応していきます。

まだ作成中とはいえ、公開しても特に問題なさそうなので、gem にして公開してみました。

また、各社の Rubocop の設定がこのような形で公開されるとお互い参考になると思いますので、気が向いた方は公開してもらえると面白いんじゃないかなぁと思っております。

http://agile.esm.co.jp/news/2016-04-01-open-esm-ruby-code-convention.html

と永和さんの記事にもあるように、各社の Rubocop の設定がもっと公開されると面白くなると思うので、みんな公開したら良いと思います!

宣伝

forkwell.connpass.com