メンバーのスキルアップ、
どうしてる?
-Java 100本ノックで新加入メンバーを鍛えてみた-
JJUG CCC Fall 2016
2016/12/03
#jjug_ccc
#ccc_f3
#Java100
自己紹介
• 株式会社ジャストシステム 福嶋 航
• Twitter @fukushiw
• Java歴約20年、JavaでWebサービス作っています
• #Java100 本ノックの人
https://github.com/JustSystems/java-100practices
株式会社ジャストシステム
• 創業37年、売上182億円、
社員平均年収884万円
• Javaのプロダクト採用は1.0から。
一太郎Ark:1996年開発着手。
• 1999年、2005年、2006年には
JavaOne Conferenceに出展
JavaOne画像引用:@IT 「JavaOneで阿波踊りを踊るジャストシステム」
http://www.atmarkit.co.jp/news/200506/30/just.html
株式会社ジャストシステム
現在、いくつものWebサービスをJavaで作っています。
などなど・・・
今日お話しすること
1.Java 100本ノックを
用いたトレーニング実例
2.ソフトウェア開発
アンチパターン7つ
1
Java 100本ノックを
用いたトレーニング実例
Java100本ノックとは?
プログラミング言語 Java に関するスキル向
上を目的とした問題集です。 具体的には、
運用環境で安定稼働でき、かつ、保守性・
拡張性に優れたコードがより多く生産できる
ようになることを目指しています。
Javaを初めて使う方から中級者までをメイン
ターゲットにしています。
Java100本ノック 目次
001-010:はじめの一歩
011-040:言語仕様
041-060:コアAPI
061-080:複合・Java EE
081-090:ライブラリ
091-099:フレームワーク
100 :Webアプリケーションの作成
Java100本ノック例えばこんなの(1)
Java100本ノック例えばこんなの(1)
解答例
jar cfe ${JARFILE} Answer010 -C ${CLASSES} Answer010.class
Java100本ノック例えばこんなの(2)
Java100本ノック例えばこんなの(2)
解答例
medals.forEach(System.out::println);
Java100本ノック例えばこんなの(3)
Java100本ノック例えばこんなの(3)
解答例
「等価なオブジェクトは等価なハッシュ・コードを保持する必要がある」と
いうhashCodeメソッドの汎用規約に従う必要があるため
java.lang.Object#equals()
java.lang.Object#hashCode()
のAPIドキュメント参照
ある日
新メンバーがあらわれた!
      たたかう       じゅもん
    ▶どうぐ         にげる
 みんな
 がんばれ
ふくしまは Java100本ノックを つかった!
トレーニング内容
• 被験者
• Java歴数ヶ月のエンジニア(20代前半)
• 課題
• Java100本ノックを001番から順番に実施
• 期間
• 1ヶ月
• サイクル
• 帰る前にその日できた分をPull Request
• 翌朝Pull Requestの内容について対面レビュー
• 指摘反映&再レビュー→新規課題取り組み
トレーニング結果
• 期間
• 19営業日
• 課題進捗
• 001~074のうち、019(JNI)を除く73問を完了
• スキル向上度合い(受講者の感想)
• 参考書を見ながらコーディングできるレベル
        ↓
Javaを「なんとなく」ではなく、理解しながら実装すること
ができるようになった! と同時に実装することが楽しいと
まで感じられるようになった!
トレーニング結果
• 期間
• 19営業日
• 課題進捗
• 001~074のうち、019(JNI)を除く73問を完了
• スキル向上度合い(受講者の感想)
• 参考書を見ながらコーディングできるレベル
        ↓
Javaを「なんとなく」ではなく、理解しながら実装すること
ができるようになった! と同時に実装することが楽しいと
まで感じられるようになった!
特にnullチェックなどの引数や例外をチェックするクセが身についた
新メンバーは レベルが あがった!
進捗
0
10
20
30
40
50
60
70
80
1日目
2日目
3日目
4日目
5日目
6日目
7日目
8日目
9日目
10日目
11日目
12日目
13日目
14日目
15日目
16日目
17日目
18日目
19日目
0
2
4
6
8
10
12
14
16
完了累計
(左軸)
完了
(右軸)
Java100本ノックの進め方
• (再掲)
• 帰る前にその日できた分をPull Request
• 翌朝Pull Requestの内容について対面レビュー
• 指摘反映&再レビュー→新規課題取り組み
Java100本ノックの進め方
• (再掲)
• 帰る前にその日できた分をPull Request
• 翌朝Pull Requestの内容について対面レビュー
• 指摘反映&再レビュー→新規課題取り組み
力をつけるにはレビューが大事
1行ずつ、1文字ずつ意味がある
Java100本ノックを受けてみた感想
• 参考書でJavaの知識を網羅したと思い込んでいたことに恐怖
を感じた
• Java API リファレンスを見る癖が付いた
• Eclipseの補完機能に頼らず実装できるようになった
• 単純に問に対する答えが分からないから難しいのではなく、 使
用するコマンド・クラス・APIなどを正しく理解した上で、 正しく
使用しなければ解けない問題が多いため難しい。
• 問題が難しい分、解けた時には、なるほどといった爽快感が
あった。
• 今までJavaを学習してきた中で、100本ノックのような問題集
にもっと早く出会えていたら、Javaの理解スピードは遙かに違っ
ていただろうと思った。
※個人の感想です
Java100本ノックを受けてみた感想
• 参考書でJavaの知識を網羅したと思い込んでいたことに恐怖
を感じた
• Java API リファレンスを見る癖が付いた
• Eclipseの補完機能に頼らず実装できるようになった
• 単純に問に対する答えが分からないから難しいのではなく、 使
用するコマンド・クラス・APIなどを正しく理解した上で、 正しく
使用しなければ解けない問題が多いため難しい。
• 問題が難しい分、解けた時には、なるほどといった爽快感が
あった。
• 今までJavaを学習してきた中で、100本ノックのような問題集
にもっと早く出会えていたら、Javaの理解スピードは遙かに違っ
ていただろうと思った。
ヨイショォオォォォォ!!
※個人の感想です
どのように活用すべきか
• 基本
• 回答→Pull Request→レビューのサイクル
• オンデマンドで被験者の相談に乗る
• レビューで鍛える
• レビューの場=スキルアップの場
• 教える側も本質を正しく理解していないといけない
• 指摘だけではなく、よくできたところを伝える
• 「コメントがよく書けた!」
• 「1メソッドが短くていいね!」
• 「この命名はわかりやすいね!」
Java100本ノックは基礎を学ぶもの
• 次は実践
• 実践では何に気をつけるべきか
2
ソフトウェア開発
アンチパターン7つ
社内の複数のプロジェ
クトに関わってきたら、
気づいてしまった
ひとつ関われば自分がわかる
ひとつ関われば自分がわかる
ふたつ関われば全てが見える
ひとつ関われば自分がわかる
ふたつ関われば全てが見える
みっつ関われば…アンチパターンが見える
ひとつ関われば自分がわかる
ふたつ関われば全てが見える
みっつ関われば…アンチパターンが見える
見える見えるー嵌まる様
アンチパターンを作るきっかけ
• 複数のプロジェクトに関わるうちに「あそこがイクナイ」
「ここがイクナイ」という事例がたまってきていて、これ
をバネに各開発チームのスキルアップが必要と感じて
いた。
• そんな折、「SQLアンチパターン」の社内読書会に
@t_wada さんにお越し頂く機会があり、そこで、
  アンチパターンには名前をつけるとよいです
というお言葉を頂戴した。
アンチパターンを作るきっかけ
• 複数のプロジェクトに関わるうちに「あそこがイクナイ」
「ここがイクナイ」という事例がたまってきていて、これ
をバネに各開発チームのスキルアップが必要と感じて
いた。
• そんな折、「SQLアンチパターン」の社内読書会に
@t_wada さんにお越し頂く機会があり、そこで、
  アンチパターンには名前をつけるとよいです
というお言葉を頂戴した。
これ、使えるんじゃないだろうか?
社内のQiita:Teamで共有してみた
今日お話しする部分
1
シャイ・メッセージ
何が起きたかは生ログで
シャイ・メッセージ(何が起きたかは生ログで)
本当にあった怖い話
ログ監視システムからアラートメールが到着。肝心のメッセージ部分には
      java.lang.NullPointerException: null
とだけ書かれている
!?
ユーザーへの影響は?
何が起きているのかサッパリ分からん・・・
シャイ・メッセージ(何が起きたかは生ログで)
本当にあった怖い話
ログ監視システムからアラートメールが到着。肝心のメッセージ部分には
      java.lang.NullPointerException: null
とだけ書かれている
!?
ユーザーへの影響は?
何が起きているのかサッパリ分からん・・・運用環境に乗り込んでログを確認・・・(初動調査に遅れ)
シャイ・メッセージ(何が起きたかは生ログで)
解決策:例外スロー時・ログ出力時のそれぞれで、
      何が起きて何ができなかったかを記載する
例外をスローするときは何が起きたかをメッセージに入れる
throw new ApiException("api server did not respond for " + retryCount + " times");
ログ出力時にどこで何の処理ができなかったかを記述する
LOGGER.error("Failed to retrieve the score from database.", e);
2
リ・インベンティング
・ザ・ホイール
無駄な独自ロジック
リ・インベンティング・ザ・ホイール(無駄な独自ロジック)
本当にあった怖い話
渡された日付の前日が所属する年
月を求めて欲しい
OK
できたよ
・・・2016/01/01入れると
2016年0月ってなるんだけど・・・
リ・インベンティング・ザ・ホイール(無駄な独自ロジック)
本当にあった怖い話
渡された日付の前日が所属する年
月を求めて欲しい
OK
できたよ
・・・2016/01/01入れると
2016年0月ってなるんだけど・・・
String newMonth =
Integer.parseInt(inputString.substring(3,5)) - 1;
return newYear + "年" + newMonth + "月";
リ・インベンティング・ザ・ホイール(無駄な独自ロジック)
本当にあった怖い話
渡された日付の前日が所属する年
月を求めて欲しい
OK
できたよ
・・・2016/01/01入れると
2016年0月ってなるんだけど・・・
String newMonth =
Integer.parseInt(inputString.substring(3,5)) - 1;
return newYear + "年" + newMonth + "月";ロジック作っちゃってる・・・!
リ・インベンティング・ザ・ホイール(無駄な独自ロジック)
補足:Date and Time API を使えば以下の通り(※例外未考慮)
return LocalDate.parse(
inputString, DateTimeFormatter.ofPattern("yyyy/MM/dd")
).plusMonths(-1L).format(
DateTimeFormatter.ofPattern("yyyy年MM月")
);
解決策:標準SDKやよく使われているライブラリを使用する
今回の場合、標準SDKであるSimpleDateFormatクラスや
Calendarクラスを使えばなんのことはなくできる処理です。標準SDK
以外のライブラリを使うまでもありません。
標準SDKが第1の選択肢です。ちまたのユーティリティライブラリが第2
の選択肢です。後者の場合、使用の前にライセンスの確認が必要で
す。
3
リーゾンレス・
トラスト
nullチェックしない
リーゾンレス・トラスト(nullチェックしない)
本当にある普通の話
実は、現場で起きている例外で一番多いのが、
NullPointerException
リーゾンレス・トラスト(nullチェックしない)
本当にある普通の話
実は、現場で起きている例外で一番多いのが、
NullPointerException
リーゾンレス・トラスト(nullチェックしない)
The Checker Framework の @NonNull や
Kotlin を使うという解決策もあります。
解決策:nullチェックを入れる
nullチェックを入れない代わりに、nullチェックをしなく
てよい理由をコメントしてもよいです。にするのがよい
です。
4
デコイ・コード
ソースコードのコピペ
デコイ・コード(ソースコードのコピペ)
本当にある普通の話
機能追加、今あるものに影響が出ない
よう、元のコードをコピーして改変せよ
了解しました
あ、ここにバグがあるや、
修正しよう
あれ? 直したはずがまだバグコードが
あるぞ?
デコイ・コード(ソースコードのコピペ)
本当にある普通の話
機能追加、今あるものに影響が出ない
よう、元のコードをコピーして改変せよ
了解しました
あ、ここにバグがあるや、
修正しよう
あれ? 直したはずがまだバグコードが
あるぞ?
バグA を たおした!
バグA の かげから バグB が あらわれた!
デコイ・コード(ソースコードのコピペ)
本当にある普通の話
機能追加、今あるものに影響が出ない
よう、元のコードをコピーして改変せよ
了解しました
あ、ここにバグがあるや、
修正しよう
あれ? 直したはずがまだバグコードが
あるぞ?
バグAをたおした!
バグAのかげからバグBがあらわれた!
メンテナンスコスト ∝ ロジックコピペ回数
デコイ・コード(ソースコードのコピペ)
解決策:Once And Only Once
コードの重複をしないように工夫します。
例えば、旧ロジックと新ロジックの共通部分
をスーパークラスで実装し、サブクラスで違う
部分だけを実装するようにします。
当然、リファクタリング前にテストコードを書い
てデグレ防止対策をする必要があります。
5
ナム・トゥ・イエロー
警告無視
ナム・トゥ・イエロー(警告無視)
本当にある普通の話
• @SupressWarningsがクラスについてる
• 警告は普通に無視。もしくは気づかない。
Eclipseだと黄色になるだけで実行できるし痛くもかゆくもない。
ナム・トゥ・イエロー(警告無視)
本当にある普通の話
• @SupressWarningsがクラスについてる
• 警告は普通に無視。もしくは気づかない。
Eclipseだと黄色になるだけで実行できるし痛くもかゆくもない。でもいざDeprecatedのものが消えたりするとそのとき大騒ぎ
ナム・トゥ・イエロー(警告無視)
解決策:コンパイラが出す警告は全て解消する
ビルドのログを見て警告が出ていないことを毎回必ず
確認するようにします。一杯たまると大変なので、
ちょっとずつビルドして、警告が出たらすかさずつぶす
ようにするのがよいです。
6
エングリッシュ
奇妙な英語
エングリッシュ(奇妙な英語)
本当にあった怖い話
• public void regist(User user)
• public boolean isExist(User user)
A:「registでしょ?」
B:「えっ?」
A:「えっ?」
エングリッシュ(奇妙な英語)
本当にあった怖い話
• public void regist(User user)
• public boolean isExist(User user)
A:「registでしょ?」
B:「えっ?」
A:「えっ?」
「キラキラ変数名」とかいう言葉も世の中にはあるようで・・・ (ノД̀)
エングリッシュ(奇妙な英語)
便利なツール
• codic
https://codic.jp/
PascalCase, camelCase, snake_caseなど
  かゆいところに手が届いているところがニクい
• IDE
例:Android Studio →
エングリッシュ(奇妙な英語)
便利なツール
• codic
https://codic.jp/
PascalCase, camelCase, snake_caseなど
  かゆいところに手が届いているところがニクい
• IDE
例:Android Studio →
• ATOK
日本語入力してF4
7
ミミック
おかしいコードの増殖
ミミック(おかしいコードの増殖)
本当にあった怖い話
リーダー「前担当のソースを参考にしてみて」
メンバー:コピーして必要なところだけ修正
~レビューにて~
リーダー「なんでthrowするのがRuntimeException?」
メンバー「だって前のコードを参考にしろという指示だったし、
そもそも何やってるのかわからないところはそのままにし
ています」
ミミック(おかしいコードの増殖)
本当にあった怖い話
リーダー「前担当のソースを参考にしてみて」
メンバー:コピーして必要なところだけ修正
~レビューにて~
リーダー「なんでthrowするのがRuntimeException?」
メンバー「だって前のコードを参考にしろという指示だったし、
そもそも何やってるのかわからないところはそのままにし
ています」
あなたが書いたコードはコピペであってもあなたのものですから!
ミミック(おかしいコードの増殖)
解決策:最善なコードを生産する
前任者から引き継いだコードがひどいシロモノだった、というの
はよくある話です。ひどいコードスタイルをそのまま受け継ぐと
負の遺産が増えるばかりです。自分がコードを書くところは自
分の責任ですから、自分が最善と思えるコードを書き、新し
く作るところだけでも清らかにしていくことが重要です。
まとめ
本日お話ししたこと
メンバーのスキルアップ、
どうしてる?
本日お話ししたこと
1.Java 100本ノックを
用いたトレーニング実例
2.ソフトウェア開発
アンチパターン7つ
We are Hiring!!

メンバーのスキルアップ、どうしてる? − Java 100本ノックで新加入メンバーを鍛えてみた −