IntelliJ を使って Pull Request をレビューする

言いたいことはタイトルが全て。

IntelliJ には GitHub と連携して Issue や Pull Request を見れる機能があり、しっかりコードレビューする際は GitHub のサイト上ではなく IntelliJ 上で行うようにしている。この IntelliJ でレビューを行うことはサイト上で行うよりも体験が良く、便利に思っていた。使い始めた頃は Pull Request の一覧やコメントを書く程度だったが、先日のバージョン2020.2のアップデートでついにレビュー関連の機能が完全にサポートされたので、これを機に IntelliJ 上でレビューを行う体験の何が良いかについて紹介したい。

blog.jetbrains.com

便利だと感じている点は4つ。以下説明していく。

  • 手元に Checkout せずに済むこと
  • 定義/参照ジャンプなどの IntelliJ の機能が使えること
  • IntelliJ の 差分表示が見やすい
  • IntelliJ上でレビュー作業の全てが完結すること

手元に Checkout せずに済むこと

Checkout せずに済むことは言葉の通りで、GitHub 上で見える差分以上に見たくなった時に手元に Checkout する場面はあると思う。この時始めから IntelliJ で Pull Request を見ていれば Checkout のコマンドを打つひと手間無く差分の周辺コードを見に行ける。

最近は GitHub CLI で簡単に Checkout できるようになっているので、この点はあまり推す点でもなくなってきているのかもしれない*1

定義/参照ジャンプなどの IntelliJ の機能が使えること

一押しはこれ。IntelliJ 上で差分を見れることで、エディタ上で未使用変数・スペルミスのハイライト、コードジャンプといった機能を使いコードを見ていけるのが便利に感じている。 GitHub 上だけでレビューしていると未使用変数やスペルミスは見落としがちで、この点は非常に助かっている。コードジャンプも GitHub 上だとブラウザの検索でメソッド名を探すといった頑張りをしなければいけなかったことが、普段のコードを読むのと同じ体験で見ていけるのは大きなメリットだと思う。

ここに書いたメリットを GitHub 上でも得られるようになってきている*2*3が、普段仕事で書いている Perl はこれらのメリットが得られにくい。この点 IntelliJPerl プラグインは優秀で、ここで書いた機能は全て提供されている。詳しくは以前書いたエントリを参照してもらいたい。

benevolent0505.hatenablog.com

差分表示が見やすい

機能の話ではあるが差分表示の見やすさは特に紹介したい。個人的に GitHub の差分表示はもっとも見やすいとは言いづらく、もっと良くなってほしいと思う点だった。 IntelliJ の差分表示は見やすく、どこに何が追加・削除されたのか、差分の周辺はどうなっているのかが見やすいと感じている。文章で伝えにくい点なので、ヘルプは画像検索の結果を見てもらいたい。

IntelliJ上でレビュー作業の全てが完結すること

Checkout の話にも通じるが、ブラウザとエディタの行き来が無くなり IntelliJ だけでレビュー作業の全てが完結できるのは、開発の効率化という面で大きなメリットだと思う。 この話は単に手間が減ることだけでなく IntelliJ (IDE) が開発の起点になるということ だと思う。別に IntelliJ が無くてもレビューや他の開発は出来るが、IntelliJ にまとめ上げることで作業を集中させ、開発を行いやすくできるのではないかと思う。

IDE とはなんなのかという話については別の方がまとめており、なるほどなと思ったのでそちらを紹介しておく。

irof.hateblo.jp

まとめ

IntelliJ で Pull Request をコードレビューするのが便利だと思う点について書いた。普段使っているツール上でレビューできる良さはやってみないとイメージしづらいものも多いと思うので、既に IntelliJ を使っている人は試してみると良いと思う *4。 また IDE が開発の起点になることに軽く触れた。元々 IntelliJ をデフォルトでコーディング支援の整ったエディタ程度にしか思っていなかったが、レビュー関連の機能を使ってからは IntelliJIDE であるということを意識するようになった。IDE は開発を行いやすくするツールであることは今後も意識していきたいと思う。

cspell でレポジトリの typo 判定一覧を出力する

Pull Request のレビューなどで typo を指摘することがあるだろうが、typo の指摘をしてもマイナスをゼロにするレビューコメントが一つ増えるだけであまり嬉しくない。

こういった無用なレビューを避けるために手元のエディタでスペルチェッカーが動かしている場合も多いと思う。最近なら多くのチームメンバーが VSCode を使っていて、レポジトリに .vscode を追加するだけで推奨拡張機能を皆のエディタに入れられるようになったので大変便利*1

Code Spell Checker - Visual Studio Marketplace

しかしこういったスペルチェッカーは造語や辞書に登録されていない単語を検知してしまうので、我々にとって誤検知であることが多い。 Code Spell Checker は設定ファイルに allowlist を記述でき、typo 判定してほしくないキーワードを登録できる。 「よし、これで導入だ」といきたいところだが、せっかくならキーワードの登録も同時に行ってしまいたい。その時に試したやり方を残しておく。

cspell を使う

Code Spell Checker は内部で cspell というライブラリを使っていて、npm でコマンドラインツールとしても配布されている。元々この拡張のために作ったツールをコマンドラインでも使えるように提供しているらしい。

www.npmjs.com

使い方は素朴でディレクトリを指定したりファイル名を直接指定すれば OK 。今回は一度単語リストが出せれば良いので npx 経由で使ってみた。

$ npx cspell <filename>

あとはお好みに合せてファイル名を指定すれば完了。 git レポジトリだったら git ls-files とかで拡張子を指定しつつファイル一覧を取得すると楽だと思う。例えば Perl だったらこんな感じになる。

#!/bin/sh

files=$(git ls-files '*.pm' '*.pl' '*.t')
exec npx --quiet cspell --wordsOnly --unique --no-summary $files

単語の一覧だけ出したいので --wordsOnly--no-summary, --unique を指定した。このままだと npx の出力も出てしまうので、 --quiet を付けると良い。

「よしよし、これで」と思ったが、普段触っているレポジトリで試してみると結構な数の語が検出されてしまい、全部 allowlist に載せるのは厳しい。もちろん typo がたくさんあるわけではなくて、 subtest などのライブラリ特有のキーワードが typo 判定されてしまったため。頻出するキーワードが typo 判定されてたらイライラしてコードの質が下がることになりかねないと思う()。

そこで作戦を変えて、頻出語順に出力し上位20件程度をリストに加えるやり方にした。

#!/bin/sh

files=$(git ls-files '*.pm' '*.pl' '*.t')
exec npx --quiet cspell --wordsOnly --no-summary $files | sort | uniq -c | sort -nr

--unique を指定するのは止め、昔ながらの UNIX コマンドの組み合わせで頻出語を出すようにした。これで allowlist に登録すると良いキーワードを判別しやすく、理由を持って追加できるようになった。

実例

試しにインターン課題のサンプルアプリケーション go-Intern-Bookmark でリストを出してみる。

~/repos/src/github.com/hatena/go-Intern-Bookmark
$ ./spellcheck.sh
  43 hatena
  13 graphql
  12 sqlx
   7 stretchr
   7 signup
   6 signin
   6 csrf
   4 tmpl
   4 jmoiron
   4 bcrypt
   4 Tmpl
   3 nosurf
   3 graphiql
   3 Signup
   3 Signin
   3 Queryx
   3 Graphql
   2 entrys
   2 attatch
   1 unmatching
   1 justinas
   1 fmsec
   1 dimfeld
   1 UUID
   1 CSRF

コード量が少ないためかおびただしい件数が検出されることはなかった。 GraphQL みたいな技術用語を検出するのは結構予想通りだが Hatena はなるほどという気持ちになった。 Go だとレポジトリ名がモジュール名に含められるので、だいたいこうなってしまいそう。

まとめ

cspell でレポジトリの typo 判定一覧を出す方法を書いた。 cspell 意外に便利そうで、 README にあるように Git の commit-hook や CI でチェックするようにしても効果的だと思う。

参考

*1:ただ僕はIntelliJEmacsを使っている

君はあのコンマ演算子を知っているか?

僕は知らなかったです。

Perlで遭遇

次のようなPerlのコードを読んでいるときに思ってなかった挙動をした。

my $x = ('a', 'b');
$x  # => ??

始め以下のような想定をして $x には 'a' が入るのだと思っていた。

  1. 左辺がスカラコンテキストなので、右辺もスカラコンテキストになる
  2. 配列の区切りの最初の値が入り $x には 'a' が入る
  3. 'b' はどの変数にも入らず捨てられる

しかし実行してみると $x には 'b' が入る。

my $x = ('a', 'b');
$x  # => 'b'

これはどういうことかと思い調べてみると、どうやらコンマ演算子というものがあるらしい。perldocを引いてみると

perldoc.jp

二項演算子の "," はコンマ演算子です。 スカラコンテキストではその左引数を評価し、その値を捨てて、 それから右引数を評価し、その値を返します。 これはちょうど、C のコンマ演算子と同じです。 リストコンテキストでは、これは単にリスト引数の区切り文字で、 双方の引数をそのリストに挿入する働きがあります。 これらの引数も左から右に評価されます。

そんなのあるの……。つまりさっきのコードは以下のような流れで 'b' が入る。

  1. 左辺がスカラコンテキストなので、右辺もスカラコンテキストになる
  2. 'a', 'b',二項演算子コンマ演算子として働く
  3. そのため 'a' を評価し値を捨て、 'b' を評価し値を返す
  4. そして $x には 'b' が入る

という流れ。

恥ずかしながら2年弱Perlを書いててコンマ演算子のことは初めて知った……。あまりこういうコードを書く機会は無いだろうけどミスってこのようなコードを書いてしまった時は意図しないハマりポイントになりそうだなと思った。

ちょっと待てよ……

Perlのハマりポイントを知ったところで、さっきのperldocの文を思い出してみると……。

これはちょうど、C のコンマ演算子と同じです。

ということはC言語やそれ以外の言語にもあるということではないだろうか?そう思って雑にググってみるとWikipediaがヒットした。

コンマ演算子 - Wikipedia

CやC++をめきめき書いたことは無いのでなるほど〜といった感想程度だったけど、次のコード例はちょっと面白い。

int a=1, b=2, c=3, i;   // このコンマは演算子としてではなくセパレータとして作用する
i = (a += 2, a + b);    // aに2を加算した後、a+b = 3+2 をiへ代入する                                    ... a=3, b=2, c=3, i=5

ちょっとしたコード短縮テクニックなのかなと思ったけど、Twitterで調べてみたら定期的にツイートがある。CやC++ということは競技プログラミングの界隈だと普通に知られたテクニックだったりするのだろうか?

コンマ演算子 - Twitter Search

お前もか〜〜

見つけてしまった瞬間「マジかよ……」と思ってしまったのだけれ、JavaScriptにもコンマ演算子は存在していた。雰囲気は同じ感じで詳細はMDNを見ればよさそう。

developer.mozilla.org

Minifierとかでコードが圧縮された後だとこんな感じのコードが生成されているのかもしれないなと思った。

終わりに

知らない演算子を発見するの結構新鮮な気分だった。PerlJavaScriptも仕事で書いているけど、言語の仕様を上から下までさらって覚えるということはしたことないので他にもこういった発見は今後もあるんだろうなと思った。 (あとJavaScriptオチ担当として優秀な気がする)

iTerm2をやめてTerminal.appを使うようにした

タイトル通りです。

Macを使い始めてからずっとターミナルエニュレータとしてiTerm2を使ってきたのだけど、iTerm2じゃなくても別によいなと思ったので始めから入っているTerminal.appを使い始めた。 前からiTerm2じゃなくていいなと思ってたけど止めようと思う決定的な理由も無くてダラダラ使い続けていた。しかし先日のiTerm2の脆弱性の原因を見て、tmux統合の機能使ってないのに巻き込まれみたいな感覚になるのちょっとな……と思ったので止めることにした。

iTerm2を止める理由もTerminal.appにする理由もそこまで無くて、挙げてもこれくらい。

  • iTerm2は色々機能があるみたいだけど全然使ってない
  • tmux統合機能があるけど、自分はscreenを使っているので必要無い
  • むしろ設定することがそんなにないTerminal.appの方が良いのでは?

Terminal.appを使うようになって困ったことな今のところ無くて、ランチャーアプリで立ち上げるときに「iterm」と打ってしまうくらいでじきに慣れると思う。 困ること本当に無くて、iTerm2の機能全然使えてなかったんだなってことを改めて実感した。 しばらくこれで使ってみて、やっぱりあの機能ほしかったなと感じたらiTerm2に戾るかも。

builderscon tokyo 2019に参加して、小学生の時見学したスーパーカミオカンデのセッションを聞いて無闇に感動してしまった

これはbuilderscon tokyo 2019の感想エントリの名を借りた自身の思い出感情吐露エントリです。

builderscon tokyo 2019に参加しました。今回が初参加だったのですが、テーマの「知らなかった、を聞く」の名の通り普段業務やちょっと興味がある程度の関心では知ることのなかった領域の話を聞けてとても刺激的だった。

builderscon.io

自分は特にyhayatoさんの「スーパーカミオカンデの開発と運用」が面白いと感じて、スーパーカミオカンデで観測したデータを集計する際の気にする数値のオーダーが全然違ったり、ケーブルの長さが異なると伝送にかかる時間が変わってくるので長さを全部揃えたり、普通に使われるネットワークスイッチが自分達のユースケースにマッチするものが無くものを検討したりだとか、普段触れるものとのスケールの違いを感じさせる発表でとても面白かった。

この発表ただ面白い以上に嬉しいの感情があり、実は14年前の小学5年生だった時にスーパーカミオカンデの見学に行く機会があって、まさにあの光電子増倍管の並ぶ水タンクの上を見学した経験があった。 当時の感想は中やたら寒いなとか、この下にあのランプが並ぶ水槽があるの?へー(ポカーン)だったり、宇宙関係の実験施設でとにかく中々見学出来る機会の無い場所ですごいらしい程度の感想しか無かったけど、それから年月が経ってWebエンジニアの職に就いてビルコンのセッションで再会して、技術者目線の感想が出たり面白さを感じること出来たのが良かったしすごく嬉しかった。

当時も小学生なりに宇宙すごいみたいなスケールの大きさを感じていたと思うけれど、今は具体的に観測したデータをどう処理するのかといった話を聞いて普段触れるものとの違いを感じている。これは自分の関心の領域が変わってきたことと、それを理解できているんだなってことに気がついて、自身の年月の経過を感じて無闇に感情的になってしまった。

小・中となんとなく理科楽しいとやってきて、高校の時にコンピュータに出会い大学で情報系、現在Webエンジニアと来たけど、まさかここで小学生の時の理科体験の1つと再会するの中々感動的だなと思う。


全ての体験が良くて、10数年前に見学に行った施設の話をビルコンみたいな場で再会したことや、目線が理科好き少年から技術者になったことや、もちろんトークが素人でもわかりやすくエンジニアも楽しめるものになってて最高だったのも良くて、全部最高だった。 今年のゲストスピーカーは僕にとってすごく嬉しいのチョイスでした。運営の皆様本当にありがとうございます。


最初の繰り返しになるけど builderscon 初めて参加して、普段触れることが無さそうな話に触れられるのめっちゃいいなと思っていて、こういうカンファレンスにどんどん参加したいと思ったし、機会があれば自分も話してみたいなと思った。

運営の皆様本当にありがとうございました!!!

IntelliJでPerlの変数宣言が複数続いた際に=の位置を揃える設定

普段Perlを書くときにIntelliJPerl pluginを使って書いているのだが、便利なことにIntelliJReformat Code時にPerl::Tidyを使ってReformatしてくれるらしい。

しかしReformatしてみたところ、変数宣言複数続いたときに = イコールの位置を揃えてくれないので、どうしたものかと困っていた。

例えば以下のような変数宣言のときに

my $short = 'short variable';
my $long_long_long = 'long variable';

= イコールの位置が揃うようにReformatしてほしい。

my $short     = 'short variable';
my $long_long = 'long variable';

あれこれ見てみたらプラグインPerl::Tidyの設定が悪いわけではなく、IntelliJ側のCode Styleの設定のせいではないかと疑ってみた。試しに設定を探してみたところどんぴしゃで、思い通りにReformatされるようになった。 設定方法は以下の通り。

  • Preferences -> Editor -> Code Style -> Perl5 にいく
  • Wrapping, Braces & Alignments のタブを選択
  • Assingment expressionAlignmentDon't align から On consecutive line に変更

これで上記のフォーマットが実現出来た。 設定方法に関してはIntelliJのバージョンによって設定までのとどりつき方が変わることもありそう。

IntelliJを使ってPerlアプリケーションの開発をする

これは、はてなエンジニア Advent Calendar 2018 23日目の記事です。

昨日は id:tkzwtks さんで AWS Step Functionsを利用してAWS BatchやFargateのタスクを起動する でした。

こんにちは。普段はマンガチームでGigaViewerの開発をしています、id:miki_bene といいます。マンガチームやGigaViewerについてはこちらの記事などをどうぞ。 仕事ではPerlを使ってアプリケーション開発をしており、Perlを書くのにVimEmacsのようなテキストエディタ拡張機能を入れて書くのではなくIntelliJを使って開発をしています。始めはEmacsを使って開発をしていましたが、IntelliJを使うようになって感じ始めた便利さやIDEを使うメリットをご紹介します。

何故IntelliJ?

まず、IntelliJを使うようになったきっかけを説明します。Perlを書き始めて最初の内はEmacsに拡張を入れて書いていましたが、

  • バッファ内の文字列や拡張で定義されているトークンの補完でしか対応していないため、十分な補完を行うことが難しい
  • gtagsなどを使ったタグジャンプで定義ジャンプを行うため、時々不正確なジャンプをしてしまう

といった悩みを感じていました。Perlを本格的に書き始める前はScalaIntelliJを使って書いていたので、プログラミング言語の差だけでなく補完やコードジャンプ・リファクタリングなどといったコードを書く際の体験の差が明確にあったのも理由です。 そんな中ふと、「最近はPHPRubyPythonのような動的型付けの言語でもIntelliJベースのIDEがあるのだから、Perlにもあるのではないか」と思ったのがきっかけです。そうして見つけたのがIntelliJPerlプラグインです。

メリット

ここからはIntelliJを使ってPerlを書くことのメリットについて紹介します。

まず上げたいこととして、当たり前なことなのですがIntelliJの機能に乗っかることが出来ることですは最大のメリットだと思います。ざっと上げるだけでも

などがあります。IntelliJの静的解析の機能を使って実現されているので、正確な補完や定義ジャンプ、リファクタリングが行えます。これはかなりの体験の改善で、悩みに上げていた正確さを改善するだけでなく、GUIベースで操作出来ることの簡単さや高機能なリファクタリングツールを手に入れることが出来ました。

またPerlプラグイン独自の機能としてアノテーションがあります。プラグインPerlの構文に沿うコードは解析でき補完も効きますが、メソッド定義時にSmart::Argsなどを用いてPerlの一般的なメソッド定義に沿わなくなった場合は補完が効きません。例えば以下の2つのメソッド定義の場合、 Smart::Args を用いたfind_by_id_with_smart_args は補完されません。

package My::Package;
use Smart::Args qw(args);

# 解析可能で My::Package->find_by_id() の呼び出しが補完可能
sub find_by_id_with_normal {
    my ($class, $id) = @_;
    ...
}

# 解析不可能で My::Package->find_by_id() の呼び出しが補完できない
sub find_by_id_with_smart_args {
    args my $class => 'ClassName',
         my $id    => 'Int',
         ;
    ...
}

その様な場合は #@method というコメントをメソッド定義の直前に書いて、アノテーションとしてプラグイン側に伝えます。そうすることで、Smart::Args を使った場合でも補完されるようになります。

# アノテーションコメントを付けることで、補完できるようになる
#@method
sub find_by_id_with_smart_args {
    args my $class => 'ClassName',
         my $id    => 'Int',
         ;
    ...
}

Perlの解析の難しさをアノテーションを使って補っている形のため若干の面倒さはありますが、アノテーションに続けてメソッド自体のコメントを書くということを半強制できているため、副次的なメリットもあるなと感じています。

まだ不便な所

IntelliJを使ったメリットを紹介していきましたが、まだまだ解消できていないものもあります。

補完やコードジャンプといった機能は静的解析によって受けている恩恵のため、通常の構文とは異なるSmart::ArgsModule::Functionsといった動的に解決するようなモジュールの利用した場合は、補完や定義ジャンプなどが行えません。当然文字列結合をしたクラス読み込みやメソッド呼び出しなどのメタプログラミングを行っている部分も同様です。 またチーム内で自分しかIntelliJを使っていないことで起こることもあります。全てのメソッドにアノテーションが付いているわけでは無いため、多くのメソッドは補完がされないといったことや、逆にチームメンバーからは僕だけ不思議なコメントを付けているように見えて、レビューで指摘されたりといったこともあります。

こういった課題は新たに Smart::ArgsModule::Functions の対応プラグインを開発したり、他のエディタでもアノテーションを意味のあるようにする拡張を作ったりということで解決できますが、かなりの労力がかかり道程はまだまだ遠そうです。

終わりに

ここまでで、IntelliJを使ってPerlアプリケーションの開発をすることについてご紹介しました。チームでは今のところマイノリティのため100%快適というわけにはいきませんが、Emacsの拡張をあれこれ試していた時期と比べるとかなり改善しました。ここではコーディング時のことを中心に書きましたが、IntelliJIDEA 2018.3からGitHubのPullRequestをIntelliJから見れる機能が加わりました。

IntelliJ IDEA 2018.3 EAP: GitHub pull requests and more – IntelliJ IDEA Blog | JetBrains

最近レビューの際はこの機能を使うようにしていて、IntelliJのDiffの見やすさとエディタとの統合に驚いているところです。これは始めは考えていなかったメリットでした。これまでIntelliJのコードを書くといった部分しか使ってきませんでしたが、様々なツールの統合といったIDEの本領を発揮させていきたいと思います。

明日は id:alpicola さんです。