Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

How to track state of operand stack by FindBugs 3.0.1

Yesterday I released findbugs-slf4j v1.2.0, which supports more useful analysis based on OpcodeStackDetector.

Here I will summarize my problem and solution.

What is TOP?

Problem is that my detector could not track state of OpcodeStack, because stack becomes TOP. I cannot get elements in stack. if stack is TOP.

What TOP means? It comes from the lattice. You may refer following papers for detail:

In context of my plugin, it means that findbugs plugin cannot decide state of Item when it joins separated operation flows (e.g. after for-loop, after if-block and in catch-block). So I cannot get Item from OpcodeStack.

How to define join operation for FindBugs?

Check merge(Item, Item) method in OpcodeStack.

But if you use userValue in Item, it should be hard to join Item because this merge method just compares two userValue and set it to merged Item only when two Items are equal.

What can be solution?

In my case, I stopped using userValue. There are some alternative solutions:

  • specialKind defined in Item might be good way to mark Item
    • It has different and complex logic to merge two Items
  • Use methods in Item class, if FindBugs already track and hold its state
    • In my case, Item#getJavaClass() replaced userValue

昨今のメソッドの命名方法事情まとめ

一時期はメソッド名は動詞で始まらなければならないと言われていましたが、昨今ではJava標準APIでも動詞ではないメソッド名が散見されます。本エントリではその傾向をまとめます。

of, from(from, of, valueOf, fromString, fromNullable etc.)

fromofはEffective Javaでも触れられているように、ファクトリメソッドとして利用されることが多いようです。例えばJAX-RSでは valueOf(), fromString() といった名前のファクトリメソッドを利用します

to, as(toList, asList, toArray etc.)

主に自分自身を別の形に変換するインスタンスを返すメソッドに使います。

またJava8のCollectorsにあるような、変換・生成を担うインスタンスを生成するメソッドにも使います。こちらはプログラムを英文として読めるようにするための命名ですね(stream.collect(toList()) など)。流れるようなインタフェースを採用する際にどうぞ。

接続詞(and, or, andThen, orElse etc.)

Andやorは2つ以上のインスタンスを結合して新しいインスタンスを生成する際に利用します。古いところではHamcrestでも使われています。

Java8では関数合成(lambda同士の結合)やOptional周りでも利用されています。

if(ifPresent, xxxIfYyy)

条件に適合する場合のみ何らかの処理を実行する際に利用します。lambdaが登場したJava8から一般的になった命名と言えるでしょう。

形容詞(boxed, reversed, empty)

自分自身の状態を特定の条件に従って変化させたものを返します。またファクトリメソッドとしても使われています。

同じJava8のAPIでもPredicate.negateは動詞を使った命名になっていて、ちょっと統一感がありません。

名詞(min, max, range, iterator

主に自分自身とは他のインスタンスを返すメソッドに使われます。ファクトリメソッドとしても使われています。

本来であればfind, create, generate, ofといった単語がメソッド名に含まれているべきですが、利用頻度が高いメソッドなので省略している……という印象です。ループカウンタにiという意味のない命名をしても支障がないのと同じでしょうか。自作クラスで使うときは、慎重になったほうが良さそうです。

be動詞(isEmpty, isPresent)

boolean型フィールドのgetter、あるいは状態を表すメソッドに使われています。

その他の動詞

ごく一般的な命名です。

なお三人称単数のSをつけるかどうかは、わりとどうでもよいようです。例えばJava標準クラスでも、Sなしの命名(e.g. Set.add)とSありの命名(Set.contains)が1クラス内で混在していたりします。Sなしの命名のほうが多いので、基本的にはそちらに合わせるとよいでしょう。

JavaのStreamで末尾再帰

JavaのStreamで末尾再帰するというアイデアが今読んでるFunctional Programming in Javaで紹介されていた。

動かしてみたら、確かにStacktraceが浅いままで階乗の計算ができている。 タネはStream.iterate()で、このメソッド再帰の代わりに必要なメソッドの計算を行ってくれている。試していないがStream.generate()でも同じことができるのではないだろうか。

あまり直感的ではないが、実用的なテクニックではありそう。覚えておこう。

追記

マイクロベンチの結果、やはり素直な書き方よりは遅いようだ。アルゴリズム単体における1割のパフォーマンス劣化は、個人的には大きいように思う。

CI用語を使わないJenkins入門

Jenkinsの使い方と狙いについて話す機会があるので、自分の考えをまとめる。 時間節約と内容簡素化のため、CIとJenkinsとを分けて説明するのではなく、開発者なら共感できるであろう表現によってJenkinsとCIの双方を説明することを目指す。なお「品質」の定義について、ここでは明確には定めない。

アジェンダ

  • Jenkinsはいろんなことを自動化するサービス
    • 人間に「人にしかできないこと」へ注力させるため、機械の執事を雇って自動化する。
  • 自動化の恩恵は「省力化」と「コミュニケーション促進」
    • 省力化: 人間に「役割」へ注力させるため、Jenkinsは各種「役割」の補佐を行う。コンパイルやテスト、情報収集や統計などルーチン作業を通じて人間が思考し判断することを助ける。ゴールは「人が行うルーチン作業」と「作業完了待ちによる暇」をゼロにすること。
    • コミュニケーション促進: 「役割」間の連携を促すため、ハブとしてコミュニケーションを促進する。組織内での作業重複を排し、各「役割」に必要な情報を必要な形で提供する。ゴールはコミュニケーションによって価値を想像すること、そのサイクルを早めること。

省力化

  • 「ルーチン処理を」「何度も」「同じように」「速やかに」やることには、高い価値がある。
    • 品質を保つには、頻繁に現状を確認する(可視化する)のが近道。
    • 1日に1回確認するのと週に1回確認するのでは、問題発見の早さも対応工数も大きく変わってくる。
    • 理想は変更があるごとに確認すること。Gitを使っているなら、Pushがあるたびに確認すること。
    • これを人にやらせるのは効率が悪いだけでなく、「人にしかできないこと」の邪魔になるので、省力化が必要になる。
  • Jenkinsは機械なので、こうしたルーチン処理の実行に向いている。
    • 機械なので疲れないし教育コストが安い。指示したとおり、同じ作業を何度も間違いなく行ってくれる。
      • 人は増やすと情報を伝え教育する必要があるが、Jenkinsならサーバを追加すればそのまま性能増になる。
      • クラウドが普通になった今、サーバを追加するのは非常に簡単で安い。
      • 変化が多く資産が積み上がる現場では、そうした手法で能力増強できるのは魅力。
  • 「人にしかできないこと」とは「判断」と「成長」と「休息」
    • 判断
      • 実装。バグ修正。品質の管理。スケジュール。開発効率の見直し。開発環境や開発手法の改善。
      • 思考や判断のための材料作りは、Jenkinsでできる。コンパイル、テスト実行、静的解析、カバレッジ測定など。
      • いつ何のためにどのような判断をするのかを人間が考え、あらかじめ判断材料を機械に蓄えさせておく。
      • バグが出たら失敗する自動テストも、バグを「発見」するための判断材料と言える。人間が実装し、機械が実行する。
    • 成長
      • 成長には問題を細分化すること、仮説をたてること、検証をすること、実行すること、振り返りをすることが必要。
      • 検証と振り返りの材料を蓄積するため、「ルーチン処理を」「何度も」「同じように」「速やかに」行う。
      • 「実行」の手段としても執事は非常に有能。人に指示するよりも簡単かつ確実、チームを超えた影響も容易。
    • 休息
      • 帰って寝る
      • 時間と心に余裕がないと、新しい挑戦を始められない。
  • 人間が「判断」し「対応」するために、機械に課題と問題を「確認」「発見」「通知」させる。
    • コンパイル単体テスト、インテグレーションテスト、静的解析といった「確認」「発見」を日々行う。
    • 問題発生時にメールやIRCなどで、役割を担う人間に「通知」する。
    • 通知によって、行動サイクルの開始を早める。リリース前に気づくことで対応コストを抑え、「休息」の時間を作る。

コミュニケーション促進

  • チーム間コミュニケーションの目的=チーム開発の欠点をなくすため
    • なぜチームが必要か
      • 作るものの複雑さと開発速度を両立させるため
      • やるべきことを明確化し、役割として分担させる
    • チームの欠点とはなにか
      • 「知らないこと」が出てくる=担当外の技術・機能・業務を知らないための悪影響
      • 全体としての知識獲得スピードは向上しているはずなので、これは至極当然に発生する
      • 欠点というより、利点を得るために生じる歪みのようなもの、リスク
  • 欠点を補うために必要な物はなにか=獲得した知識の伝播と、コミュニケーションによる現状把握
    • 獲得した知識の啓蒙・汎用化(「巨人の肩」の形成)
      • 他者に対して報告・共有と言った形で知識を伝播させる
      • 知らなくても問題ないように、汎用的なインタフェースで包んでしまう
        • ビジネスニーズを知らない人でも機能破損に気づけるように、自動テストを書く
        • 技術的バックグラウンドを知らない人でも使えるように、モジュールとして提供する
        • チェックリストをいちいち確認しないでもいいように、ビルドツールに自動チェックをさせる
      • Jenkinsはそういった諸々をサポートできる!
        • 情報を満載したサイトの提供
        • 自動テストの実施
        • モジュール間依存関係の管理、依存先変更によるビルドの実施
        • ビルドツールの実行による自動チェック、ならびにチェック結果の管理・表示
    • コミュニケーションによる現状把握
      • 役割の明確化により、問い合わせコストを下げる
      • 今何をやっているかを伝え、他チームから作業を引き受け重複排除する
      • 自分が管理しているルールやチェックリストを、他チームが守っているか確認する
        • Jenkinsは現状の把握と他チーム連携のトリガーになれる。

How to upgrade Jenkins plugin to support latest LTS (1.596)

Today I've updated my Jenkins plugin, to support latest LTS version.

This article will explain what we should do to support latest LTS Jenkins.

Write dependencies on other plugins explicitly

Previously some core features were bundled in Jenkins core, but now they are independent plugins. If you need features of them, you should write dependencies in pom.xml.

  <dependencies>
    <dependency>
      <groupId>org.jenkins-ci.plugins</groupId>
      <artifactId>junit</artifactId>
      <version>1.3</version>
    </dependency>
    <dependency>
      <groupId>org.jenkins-ci.plugins</groupId>
      <artifactId>mailer</artifactId>
      <version>1.10</version>
    </dependency>

See also: Dependencies among plugins - Jenkins - Jenkins Wiki

Replace deprecated API

API which is annotated with @Deprecated should be replaced with recommended API. Check Javadoc and implementation of deprecated method, then you can find how you should replace.

In my case, I had to replace following API:

About how to use JenkinsRule, please see Unit Test - Jenkins - Jenkins Wiki.

Add <repositories> and <pluginRepositories> to pom.xml

To pass build on buildhive, we need to add both of them to pom.xml.

Gitbook v2.0.0で日本語書籍を書くときの落とし穴と回避策

Gitbookの多言語対応はまだ弱く、日本語で書籍を書く際はいくつか対応が必要です。 しかし文字化け等はないため、Markdownに慣れている人であれば充分に活用できる製品になっていると思います。

文中の意図せぬ空白

文中の改行が空白に変換されてしまうため、段落をすべて1行で書ききる必要があります。

下記プラグインで対応可能のようですが、利用時に警告が表示されます。折り返し表示可能なエディタを利用したほうが良いかもしれません。

github.com

GLOSSARY

用語集は半角空白で区切る言語のために設計されています。つまり半角空白で区切られた単位を「単語」として認識し、自動的にリンクを追加するような仕組みになっています。

このため、日本語のような単語間に空白が入らない言語の場合は、分かち書きをしないと使えません。 例えば「りんご」という言葉を用語集に追加する場合、本文には

りんごの木があり、りんごの実が3つなっていました。

ではなく、以下のように半角空白(あるいは改行)で単語を挟んで記述しなければなりません。単語が句読点の後に来る場合も、半角空白(または改行)が必要です。

# 半角空白で「りんご」を挟む
りんご の木があり、 りんご の実が3つなっていました。
# 改行でも良い
りんご の木があり、
りんご の実が3つなっていました。

7年働いた時点での私の仕事の極意

最重要

  • 実行に重きを置く
    • やらないで後悔するよりも、やって反省する。
      • 反省は成長を産み生産的だが、後悔は精神の無駄な消費。
      • 時間は有限で貴重な資源だが、たぶん今の段階では行動する前に得るものや結果を予測するのは難しい。
    • 正しい反省の方法とは何か、考え続けること。
      • 「正しく反省するために、何を記録しておくべきか」実行前に明らかにしておくこと。
      • 反省の結果は組織的な何かに落としこむ。組織構造、戦略、静的解析、自動テスト、教育など。意識しないでも巨人の肩に乗れる状況を作ることが、組織の成長につながる。
    • Done is Better Than Perfect
      • ただし、思考停止の言い訳にしないこと。詰めの甘さを擁護する言葉ではない。詰めの甘さは立場や考え方が違うひと3人くらいに意見を求めればだいたい炙り出せる。
      • 長期的視野を持ちつつ、それに引っ張られない。進展を作ること、現状を少しずつ変えることを意識する。
    • 「やる内容」ではなく「たどり着くべき結果」が大切だということを忘れないために、問題の特定と問題解決の実行にフェーズの概念を持ち込む。やりたいから仕事をやるのではなく、解決するにはこの仕事をやるべきだからやる、ということをチーム全員で意識する。
    • いつでも行動を取れるよう、自己を印象づけておきつつ周囲との繋がりを育てておく。
      • ひとりで完結する仕事はない。

人との交わり方

  • 推測の扱い

    • 議論の仮説にできる「建設的な推測」と根拠の無い「不安や期待」を分けて扱う。
    • 議論の仮説はあくまでも「仮説」であり、「前提」ではない。状況に応じてアップデートされるべき。
    • 不安や期待は上司あるいは信頼できる人に1on1で話す。それ以外の人と場所には話さない。マネジメントに限らず後輩を持つ身なら意識したい/させたいポイント。
      • 不安はコミュニケーション不足を表すシグナルであることが多い。
  • ヒューマンスキル

    • という、横文字に惑わされないこと。「みんなが幸せ」になるにはどうするか考えて行動しようという話。それだけ。
    • 「幸せの定義」「何をもって満足するか」「情報の非対称性」「優先度の違い」「面子」「私生活」などなど様々な変数が絡むのでわかりにくくなる。
      • 目的意識がバラバラだと「みんなが幸せ」という絵を描けなくなる。ヒューマンスキルの前提にはプロジェクトマネジメント、チームビルディングがある。
      • 情報の非対称性は人間が複数集まった時点で当然生じるので、情報を取りに行ったり率先して提供したりセルフブランディングしたりする必要がある。
      • セルフブランディングの理想は「あの人なら問題を解決してくれる」。機能を切り口にする「XXならなんでも分かる人」は次点。
      • 個人に敬意と関心を持つこと。個人を知らないことがチームビルディングのミスを誘発する。
    • 私は年上・目上に対して(本人にその気はないのに)面子を潰しに行く傾向にあるので自重する。日本人に対するコミュニケーションが下手だ(要らん遠慮をする)という説もある。

エンジニアとしての心構え

  • 技術的・ビジネス的な流行り廃りとのつきあいかた

    • 跳びつくのではなく、それが生まれた歴史的背景を考える。
    • その背景を自分たちが共有しているか?を落ち着いて判断する。ウリ文句には多分にポジショントークが含まれることを覚えておく。
    • どうしても跳びついてしまう人は存在する。たぶん経験の差で、デザインパターンを何にでも適用しようとするのと同じ。モチベーションを削がずに再考を促す方法は、まだ見つかっていない。
  • 武器を増やすための研究は個人で、武器を磨くための追求は仕事で

    • 課題はそれの解決に必要な武器を教えてくれない(教えてくれたとして、それからキャッチアップしているのでは遅いことがしばしば)。仕事が始まる時点で武器を知っているために、予め広い視野を持って武器を増やしておく。
      • JVMは数少ない「教えてもらった」武器。新人にはOJTでも良いので、何かひとつは渡すようにする。責任を持たせることにも繋がる。
      • ASM, Findbugs, AMD (RequireJS), Maven, Grunt, SLF4J, npm, CI, OOP, FP は自ら研究しておいたことで業務においてリードする立場になれた。
      • LLVM, GAE, Vagrant, PMD, Chef はまだ役だってないが、考察のための視野を育む上で役立った。
      • enchant.js, Travis CI, Golang, Android, Intel Edison については今のところ全く役立っていない。百発百中である必要はない。
    • 深い理解や応用は要求によって育まれる。個人で作れるツールやライブラリとは比べ物にならない要求と資源(時間)を、業務では使うことができる。
    • 重要なのは、この原則を他人に求めないこと。すべて仕事で完結させるのも正しい選択で、だから教育や自動化(人手の排除)が必要。
  • 目指すべきは専門家でも何でも屋でもない

    • エキスパートになることで、組織の部品として問題解決の手段として使いやすくなる。問題を持ち込まれやすくなる=活躍の機会が増える。
    • 何でも屋になることで、問題の本質を見抜き迅速な解決が可能になる。問題を発見したり、切り分け前の問題を持ち込まれやすくなる。
    • 真になるべきは、周囲のやる気と関心を引き出しチームとしての問題解決に貢献できる人。エキスパートとしての自分や何でも屋としての自分は道具であり手段。時には他のエキスパートにdispatchしたり、他の何でも屋に意見を求める。
  • 「技術できます」と言ってしまう

    • 自分を超える超級エンジニアが山のようにいらっしゃることをわかった上で、あえて「技術できます」と言う。
    • ”技術できる”の定義なんて存在しないので気にしない。”技術に詳しいらしい”ということを知ってもらうだけで、組織に貢献できる機会は増える。沈黙や謙遜は個人の美徳であって、チームや組織にはリターンがない。
      • ヒューマンスキル上のリスクはある。またビジネスがわからないのではという不安を持たれるので、行動で示していく。

マネジメントとしての心構え

  • とにかく聞いて話す

    • 日本人とは飲み会、中国人とは昼ごはん、というのが今のところの経験則。業務の枠を超えないと業務を向上させることはできない。
    • 自分がどう成長したいかわかっていない人がほとんどなので、3-6ヶ月かかっても良いから1on1を通じて意識を作っておく。
  • 組織として目指しているのはどこか、チームとして目指すべきはどこかを明確にする。他のチームの目標と現場も可能な限り伝える。

    • 「自分には何ができるか?」常に考えてもらう。
      • 例)Stand-up Meetingは報告の場ではなく共有の場であり、共有された問題に対して動くべきは自分であると認識させる。
  • 戦略とビジネスモデルはシンプルであるべき

    • 判断基準となるこれらは、シンプルでなければ使いまわせない。
    • 今やっているタスクが技術的に特異なことであればあるほど、基本となる「目標」を意識すること。

被マネジメントとしての心構え

  • 要求を明確に上げる

    • 「〜だったらいいな」「〜なのは嫌だな」ではなく「XXという問題がありYYで解決したいのでZZをください」と言う。「AAな理由がわからないのですが、BBなのでしょうか」と理解を確認するのも可。
    • 私の場合「仕事がつまらない」と感じたら即座に「何をやるべきと考えているか」伝えるべき。すぐに自分が思っている以上のパフォーマンス低下が出る。
  • 自分で判断せず、判断基準を提供する

    • 高台にいる人のほうが視野が広いのは当然。高台にいては見えないこと、自分だからわかることを論理的に言語化して伝える。論理的でないと、マネジメントが他のマネジメントや上司に伝えられない。
    • 判断はマネジメントに下してもらい、その判断に意見はしても文句は言わない。文句があるなら自分でマネジメントする。
  • 目標を求める

    • 目標が与えられずタスクだけ降ってくる状況は、中長期的に見てまず良いことがない。
    • 結局何をやることが顧客のため組織のためになるのか、マネジメントに考えさせる。マネジメントをマネジメントする。
  • 「マネジメントがXX(技術、自分、状況 その他)を分かってない」と言うのは非生産的

    • マネジメントにわからせろ!
    • マネジメントがそれをわかっていないのは、マネジメント個人の問題ではなく組織構造や自分の情報の扱いに起因する問題であるとも考えられる。

まとめ

  1. 実行せよ
  2. 正しく実行するためには、実行の目標とプロセスに関心を払い、役割を正しく演じよ
  3. 個人と組織の成長を促すため、常に会話し、顧客や仲間を幸せにし続けよ