メンバーのスキルアップ、どうしてる? − java...

73
メンバーのスキルアップ、 どうしてる? -Java 100本ノックで新加入メンバーを鍛えてみた- JJUG CCC Fall 2016 2016/12/03 #jjug_ccc #ccc_f3 #Java100

Upload: justsystems-corporation

Post on 21-Apr-2017

5.273 views

Category:

Engineering


3 download

TRANSCRIPT

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

メンバーのスキルアップ、どうしてる?

-Java 100本ノックで新加入メンバーを鍛えてみた-

JJUG CCC Fall 20162016/12/03

#jjug_ccc#ccc_f3#Java100

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

自己紹介

• 株式会社ジャストシステム 福嶋 航• Twitter @fukushiw• Java歴約20年、JavaでWebサービス作っています• #Java100 本ノックの人https://github.com/JustSystems/java-100practices

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

株式会社ジャストシステム

• 創業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

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

株式会社ジャストシステム現在、いくつものWebサービスをJavaで作っています。

などなど・・・

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

今日お話しすること

1.Java 100本ノックを 用いたトレーニング実例

2.ソフトウェア開発 アンチパターン7つ

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

1

Java 100本ノックを用いたトレーニング実例

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

Java100本ノックとは?プログラミング言語 Java に関するスキル向上を目的とした問題集です。 具体的には、運用環境で安定稼働でき、かつ、保守性・拡張性に優れたコードがより多く生産できるようになることを目指しています。

Javaを初めて使う方から中級者までをメインターゲットにしています。

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

Java100本ノック 目次

001-010:はじめの一歩011-040:言語仕様041-060:コアAPI061-080:複合・Java EE081-090:ライブラリ091-099:フレームワーク100 :Webアプリケーションの作成

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

Java100本ノック例えばこんなの(1)

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

Java100本ノック例えばこんなの(1)解答例

jar cfe ${JARFILE} Answer010 -C ${CLASSES} Answer010.class

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

Java100本ノック例えばこんなの(2)

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

Java100本ノック例えばこんなの(2)解答例

medals.forEach(System.out::println);

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

Java100本ノック例えばこんなの(3)

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

Java100本ノック例えばこんなの(3)解答例

「等価なオブジェクトは等価なハッシュ・コードを保持する必要がある」というhashCodeメソッドの汎用規約に従う必要があるため

java.lang.Object#equals()java.lang.Object#hashCode()

のAPIドキュメント参照

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

ある日

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

新メンバーがあらわれた!

      たたかう       じゅもん    ▶どうぐ         にげる

 みんな がんばれ

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

ふくしまは Java100本ノックを つかった!

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

トレーニング内容• 被験者

• Java歴数ヶ月のエンジニア(20代前半)• 課題

• Java100本ノックを001番から順番に実施• 期間

• 1ヶ月• サイクル

• 帰る前にその日できた分をPull Request• 翌朝Pull Requestの内容について対面レビュー• 指摘反映&再レビュー→新規課題取り組み

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

トレーニング結果• 期間

• 19営業日• 課題進捗

• 001~074のうち、019(JNI)を除く73問を完了• スキル向上度合い(受講者の感想)

• 参考書を見ながらコーディングできるレベル        ↓Javaを「なんとなく」ではなく、理解しながら実装することができるようになった! と同時に実装することが楽しいとまで感じられるようになった!

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

トレーニング結果• 期間

• 19営業日• 課題進捗

• 001~074のうち、019(JNI)を除く73問を完了• スキル向上度合い(受講者の感想)

• 参考書を見ながらコーディングできるレベル        ↓Javaを「なんとなく」ではなく、理解しながら実装することができるようになった! と同時に実装することが楽しいとまで感じられるようになった!特にnullチェックなどの引数や例外をチェックするクセが身についた

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

新メンバーは レベルが あがった!

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

進捗

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

完了累計

(左軸)

完了

(右軸)

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

Java100本ノックの進め方

• (再掲)• 帰る前にその日できた分をPull Request• 翌朝Pull Requestの内容について対面レビュー• 指摘反映&再レビュー→新規課題取り組み

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

Java100本ノックの進め方

• (再掲)• 帰る前にその日できた分をPull Request• 翌朝Pull Requestの内容について対面レビュー• 指摘反映&再レビュー→新規課題取り組み

力をつけるにはレビューが大事1行ずつ、1文字ずつ意味がある

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

Java100本ノックを受けてみた感想• 参考書でJavaの知識を網羅したと思い込んでいたことに恐怖

を感じた• Java API リファレンスを見る癖が付いた• Eclipseの補完機能に頼らず実装できるようになった• 単純に問に対する答えが分からないから難しいのではなく、 使

用するコマンド・クラス・APIなどを正しく理解した上で、 正しく使用しなければ解けない問題が多いため難しい。

• 問題が難しい分、解けた時には、なるほどといった爽快感があった。

• 今までJavaを学習してきた中で、100本ノックのような問題集にもっと早く出会えていたら、Javaの理解スピードは遙かに違っていただろうと思った。

※個人の感想です

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

Java100本ノックを受けてみた感想• 参考書でJavaの知識を網羅したと思い込んでいたことに恐怖

を感じた• Java API リファレンスを見る癖が付いた• Eclipseの補完機能に頼らず実装できるようになった• 単純に問に対する答えが分からないから難しいのではなく、 使

用するコマンド・クラス・APIなどを正しく理解した上で、 正しく使用しなければ解けない問題が多いため難しい。

• 問題が難しい分、解けた時には、なるほどといった爽快感があった。

• 今までJavaを学習してきた中で、100本ノックのような問題集にもっと早く出会えていたら、Javaの理解スピードは遙かに違っていただろうと思った。

ヨイショォオォォォォ!!

※個人の感想です

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

どのように活用すべきか• 基本

• 回答→Pull Request→レビューのサイクル• オンデマンドで被験者の相談に乗る

• レビューで鍛える• レビューの場=スキルアップの場• 教える側も本質を正しく理解していないといけない• 指摘だけではなく、よくできたところを伝える

• 「コメントがよく書けた!」• 「1メソッドが短くていいね!」• 「この命名はわかりやすいね!」

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

Java100本ノックは基礎を学ぶもの

• 次は実践• 実践では何に気をつけるべきか

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

2

ソフトウェア開発アンチパターン7つ

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

社内の複数のプロジェクトに関わってきたら、気づいてしまった

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

ひとつ関われば自分がわかる

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

ひとつ関われば自分がわかる

ふたつ関われば全てが見える

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

ひとつ関われば自分がわかる

ふたつ関われば全てが見える

みっつ関われば…アンチパターンが見える

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

ひとつ関われば自分がわかる

ふたつ関われば全てが見える

みっつ関われば…アンチパターンが見える

見える見えるー嵌まる様

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

アンチパターンを作るきっかけ• 複数のプロジェクトに関わるうちに「あそこがイクナイ」

「ここがイクナイ」という事例がたまってきていて、これをバネに各開発チームのスキルアップが必要と感じていた。

• そんな折、「SQLアンチパターン」の社内読書会に @t_wada さんにお越し頂く機会があり、そこで、

  アンチパターンには名前をつけるとよいです

というお言葉を頂戴した。

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

アンチパターンを作るきっかけ• 複数のプロジェクトに関わるうちに「あそこがイクナイ」

「ここがイクナイ」という事例がたまってきていて、これをバネに各開発チームのスキルアップが必要と感じていた。

• そんな折、「SQLアンチパターン」の社内読書会に @t_wada さんにお越し頂く機会があり、そこで、

  アンチパターンには名前をつけるとよいです

というお言葉を頂戴した。

これ、使えるんじゃないだろうか?

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

社内のQiita:Teamで共有してみた

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

今日お話しする部分

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

1

シャイ・メッセージ

何が起きたかは生ログで

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

シャイ・メッセージ(何が起きたかは生ログで)

本当にあった怖い話

ログ監視システムからアラートメールが到着。肝心のメッセージ部分には

      java.lang.NullPointerException: null

とだけ書かれている

!?ユーザーへの影響は?

何が起きているのかサッパリ分からん・・・

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

シャイ・メッセージ(何が起きたかは生ログで)

本当にあった怖い話

ログ監視システムからアラートメールが到着。肝心のメッセージ部分には

      java.lang.NullPointerException: null

とだけ書かれている

!?ユーザーへの影響は?

何が起きているのかサッパリ分からん・・・運用環境に乗り込んでログを確認・・・(初動調査に遅れ)

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

シャイ・メッセージ(何が起きたかは生ログで)

解決策:例外スロー時・ログ出力時のそれぞれで、      何が起きて何ができなかったかを記載する

例外をスローするときは何が起きたかをメッセージに入れるthrow new ApiException("api server did not respond for " + retryCount + " times");

ログ出力時にどこで何の処理ができなかったかを記述するLOGGER.error("Failed to retrieve the score from database.", e);

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

2

リ・インベンティング・ザ・ホイール無駄な独自ロジック

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

リ・インベンティング・ザ・ホイール(無駄な独自ロジック)

本当にあった怖い話

渡された日付の前日が所属する年月を求めて欲しい

OK

できたよ

・・・2016/01/01入れると2016年0月ってなるんだけど・・・

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

リ・インベンティング・ザ・ホイール(無駄な独自ロジック)

本当にあった怖い話

渡された日付の前日が所属する年月を求めて欲しい

OK

できたよ

・・・2016/01/01入れると2016年0月ってなるんだけど・・・

String newMonth = Integer.parseInt(inputString.substring(3,5)) - 1;return newYear + "年" + newMonth + "月";

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

リ・インベンティング・ザ・ホイール(無駄な独自ロジック)

本当にあった怖い話

渡された日付の前日が所属する年月を求めて欲しい

OK

できたよ

・・・2016/01/01入れると2016年0月ってなるんだけど・・・

String newMonth = Integer.parseInt(inputString.substring(3,5)) - 1;return newYear + "年" + newMonth + "月";ロジック作っちゃってる・・・!

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

リ・インベンティング・ザ・ホイール(無駄な独自ロジック)

補足: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の選択肢です。後者の場合、使用の前にライセンスの確認が必要です。

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

3

リーゾンレス・トラスト

nullチェックしない

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

リーゾンレス・トラスト(nullチェックしない)

本当にある普通の話

実は、現場で起きている例外で一番多いのが、

NullPointerException

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

リーゾンレス・トラスト(nullチェックしない)

本当にある普通の話

実は、現場で起きている例外で一番多いのが、

NullPointerException

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

リーゾンレス・トラスト(nullチェックしない)

The Checker Framework の @NonNull や Kotlin を使うという解決策もあります。

解決策:nullチェックを入れる

nullチェックを入れない代わりに、nullチェックをしなくてよい理由をコメントしてもよいです。にするのがよいです。

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

4

デコイ・コード

ソースコードのコピペ

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

デコイ・コード(ソースコードのコピペ)

本当にある普通の話

機能追加、今あるものに影響が出ないよう、元のコードをコピーして改変せよ

了解しました

あ、ここにバグがあるや、修正しよう

あれ? 直したはずがまだバグコードがあるぞ?

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

デコイ・コード(ソースコードのコピペ)

本当にある普通の話

機能追加、今あるものに影響が出ないよう、元のコードをコピーして改変せよ

了解しました

あ、ここにバグがあるや、修正しよう

あれ? 直したはずがまだバグコードがあるぞ?

バグA を たおした!バグA の かげから バグB が あらわれた!

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

デコイ・コード(ソースコードのコピペ)

本当にある普通の話

機能追加、今あるものに影響が出ないよう、元のコードをコピーして改変せよ

了解しました

あ、ここにバグがあるや、修正しよう

あれ? 直したはずがまだバグコードがあるぞ?

バグAをたおした!バグAのかげからバグBがあらわれた!

メンテナンスコスト ∝ ロジックコピペ回数

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

デコイ・コード(ソースコードのコピペ)

解決策:Once And Only Once

コードの重複をしないように工夫します。例えば、旧ロジックと新ロジックの共通部分をスーパークラスで実装し、サブクラスで違う部分だけを実装するようにします。

当然、リファクタリング前にテストコードを書いてデグレ防止対策をする必要があります。

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

5

ナム・トゥ・イエロー

警告無視

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

ナム・トゥ・イエロー(警告無視)本当にある普通の話

• @SupressWarningsがクラスについてる• 警告は普通に無視。もしくは気づかない。

Eclipseだと黄色になるだけで実行できるし痛くもかゆくもない。

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

ナム・トゥ・イエロー(警告無視)本当にある普通の話

• @SupressWarningsがクラスについてる• 警告は普通に無視。もしくは気づかない。

Eclipseだと黄色になるだけで実行できるし痛くもかゆくもない。でもいざDeprecatedのものが消えたりするとそのとき大騒ぎ

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

ナム・トゥ・イエロー(警告無視)解決策:コンパイラが出す警告は全て解消する

ビルドのログを見て警告が出ていないことを毎回必ず確認するようにします。一杯たまると大変なので、ちょっとずつビルドして、警告が出たらすかさずつぶすようにするのがよいです。

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

6

エングリッシュ

奇妙な英語

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

エングリッシュ(奇妙な英語)本当にあった怖い話

• public void regist(User user)

• public boolean isExist(User user)

A:「registでしょ?」B:「えっ?」A:「えっ?」

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

エングリッシュ(奇妙な英語)本当にあった怖い話

• public void regist(User user)

• public boolean isExist(User user)

A:「registでしょ?」B:「えっ?」A:「えっ?」

「キラキラ変数名」とかいう言葉も世の中にはあるようで・・・ (ノД̀)

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

エングリッシュ(奇妙な英語)便利なツール

• codichttps://codic.jp/ PascalCase, camelCase, snake_caseなど  かゆいところに手が届いているところがニクい

• IDE例:Android Studio →

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

エングリッシュ(奇妙な英語)便利なツール

• codichttps://codic.jp/ PascalCase, camelCase, snake_caseなど  かゆいところに手が届いているところがニクい

• IDE例:Android Studio →

• ATOK日本語入力してF4

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

7

ミミック

おかしいコードの増殖

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

ミミック(おかしいコードの増殖)本当にあった怖い話

リーダー「前担当のソースを参考にしてみて」メンバー:コピーして必要なところだけ修正

~レビューにて~リーダー「なんでthrowするのがRuntimeException?」

メンバー「だって前のコードを参考にしろという指示だったし、そもそも何やってるのかわからないところはそのままにし

ています」

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

ミミック(おかしいコードの増殖)本当にあった怖い話

リーダー「前担当のソースを参考にしてみて」メンバー:コピーして必要なところだけ修正

~レビューにて~リーダー「なんでthrowするのがRuntimeException?」

メンバー「だって前のコードを参考にしろという指示だったし、そもそも何やってるのかわからないところはそのままにし

ています」あなたが書いたコードはコピペであってもあなたのものですから!

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

ミミック(おかしいコードの増殖)解決策:最善なコードを生産する

前任者から引き継いだコードがひどいシロモノだった、というのはよくある話です。ひどいコードスタイルをそのまま受け継ぐと負の遺産が増えるばかりです。自分がコードを書くところは自分の責任ですから、自分が最善と思えるコードを書き、新しく作るところだけでも清らかにしていくことが重要です。

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

まとめ

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

本日お話ししたこと

メンバーのスキルアップ、どうしてる?

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

本日お話ししたこと

1.Java 100本ノックを 用いたトレーニング実例

2.ソフトウェア開発 アンチパターン7つ

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

We are Hiring!!