20190804のJavaに関する記事は9件です。

Docker+k8s勉強会に行ってきた話【JAZUG女子部×Java女子部】

JAZUG女子部×Java女子部コラボのDocker&Kubernetes勉強会にスタッフとして参加してきました!
Java女子部のイベントには何度か参加していたんですが、運営側での参加は今回が初めてです。せっかくなので参加レポを書いておきます。

イベント概要

【東京】【女性限定】【JAZUG女子部コラボ】Japan Tour in Summer: Java & k8s on Azure まつり by #てらだよしおがんばれ
2019-08-03(土)10:00 - 17:00
日本マイクロソフト 31階roomA
https://javajo.doorkeeper.jp/events/94041

講師:寺田佳央さん(https://twitter.com/yoshioterada)
ハッシュタグ:#てらだよしおまつり

スケジュール

午前:Dockerについてのお勉強(座学)、ハンズオンのチーム分け
午後:Azure+Docker+Kubernetesのハンズオン(モブプロ)

イベント準備

事前のスタッフ間のやり取りはSlack、FacebookMessengerでした。
当日スタッフは9:00に集合して会場設営やライブ配信の準備などをしていました。
(遠方から参加の方用にGoogleHangoutsでライブ配信したんですが、色々おぼつかなかったので今後のために勉強しておこうと思いました;;)

午前の部

午前は座学でみんなでDockerについてお勉強。
参加者30人前後で、Docker使ったことあるのは半分以下くらい、Kubernetesは初めての方が大多数でした。
コンテナってなに?からKubernetesを使うとなにが嬉しいの?まで丁寧に教えてもらえました。

午後の部 Azure×Docker×k8sハンズオン

午後は6人くらい×4チームに別れてAzureを使ったモブプロ形式のハンズオン。
Azureのアカウントを作るところからスタート。会場にチーム分の大きいモニターがなかったので、画面の共有にはTeamsを使っています。
Teamsでの画面共有初めてでしたが使いやすくて良かったです。ブラウザ版だと他人の画面を見ることはできるけど自分の画面を共有できないので、アプリ版が必要でした。

レベル感

  • Docker、Kubernetesはほとんどの参加者が未経験だったので大丈夫!
  • Javaの知識もなくて大丈夫!
  • 踏み台のLinuxサーバにssh接続してコマンド叩いたりファイル修正したりするので、Linuxは多少触ったことないと厳しいかも
  • でも多少わからないことがあってもモブプロなのでチームの仲間が助けてくれる!大丈夫!

内容

AzureにLinuxサーバを立てて、その中でDockerイメージを作る→Azureにプッシュする→Kubernetesでイメージを持ってきてアプリケーションを動かす、の流れでした。
チーム内で順番に操作者を回していきます。
Azureのクラウドシェルでssh使えるけど結構動作がもっさりしてたので、bashやTeraTermの方が快適でした。

資料や実際に動かしたシェル、アプリケーション等は寺田さんのGitHubのリポジトリからクローン。
https://github.com/yoshioterada/k8s-Azure-Container-Service-AKS--on-Azure

感想

モブプロすごく楽しかった!
最初6人だと人数が多く感じたんですが、意外とコミュニケーションも取りやすいし、途中詰まっても誰かがフォローできるので良かったです。わからなくて置いていかれる人も出ませんでした。
コンテナのバージョンの切り替えとかさくさくできて楽しかった!Kubernetesで実行したアプリケーションに実際に外部IPでアクセスして、APIのレスポンスが帰ってきた時は女子6人でわいわい盛り上がりました 笑
1日だとかなりコンテンツがぎっちりで、途中シェルの内容とか流し読んでしまった部分もあったので、改めて復習したいと思います。

イベント参加したい人!

2019/9/7(土)に開催のJAZUG9周年イベントでもDocker×Kubernetesのハンズオンを実施予定とのことです。てらだよしおまつりファイナル!
https://jazug.connpass.com/event/140843/

Java女子部の次回イベントは10月頃の開催予定ですので、そわそわお待ちください!私もそわそわ待ってます!
https://javajo.doorkeeper.jp/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DB接続設定 Spring-Boot application.properties

はじめに

直近の仕事で、Spring-Bootでアプリ開発を続けています。
application/properties にDB接続設定を記述する必要がある度にGoogleで検索しています。
直ぐに記事が見つかるので、差支えはないのですが、割と頻繁に使うので、自分の記事にも残すことにしました。(悲しいかな、年のためか覚えても直ぐに忘れてしまうのです。年齢は関係ない?!)

# MYSQL
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/DB名
spring.datasource.username=ユーザー名
spring.datasource.password=パスワード
spring.jpa.database=MYSQL # JPAを使う場合は任意。なかったら自動判断
spring.jpa.hibernate.ddl-auto=update

# PostgreSQL
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/DB名
spring.datasource.username=ユーザー名
spring.datasource.password=パスワード

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Modding】Minecraftで重要なSideの概念

はまったこと

world.createExplosion()を実行したときに、表示されていないが当たり判定だけが残っている、いわゆるゴーストブロック現象が発生してしまった。いろいろ調べたところ、ServerClientという、サイドの概念がForgeには存在しているらしい。で、それぞれのサイドでプログラムが実行されていることが分かった。こちらのリファレンスを参考にした。

サイドの種類について

大体の認識だと、クライアントというものはプレーヤーに影響するもので、サーバーというものはマルチプレイをするときに接続するものだという認識だろう。

さてここで、この二つのサイドのあいまいな点を解説していこう。

物理サーバー

物理サーバーというのは、よくdedicated server(専用サーバー)といわれるものだ。専用サーバーはminecraft_server.jarのような種類のプログラム全体のことで、操作できる画面を持たない。

物理クライアント

物理クライアントというのは、Minecraftをランチャーから起動するプログラム全体のことだ。ゲームの描画や画面操作などを担っているすべてのスレッドやプロセス、そしてサービスは物理クライアントの一部だといえる。

論理サーバー

論理サーバーはゲームの統括をする。モブのスポーン、天候、インベントリの更新、モブの知能など、ゲームの仕組みすべてを担っている。論理サーバーは物理サーバーの中にあるものだが、シングルプレイのときは物理クライアントの中で論理クライアントと一緒に実行することができる。これはServer Threadという名前で実行される。

論理クライアント

論理クライアントはプレーヤーからの入力を受け取って、それを論理サーバーに送信する役目を持っている。加えて論理クライアントは論理サーバーから情報を受け取り、その情報をプレーヤーが見えるように画面に表示する。これは、Client Threadという名前で実行される。

サイドに合わせたプログラムの実行

world.isRemote

この真偽値はどちらのサイドでプログラムが実行されているかを調べるものである。この真偽値で調べられるのは、論理サーバーか論理クライアントかどうかだ。論理クライアントだったらtrueを返し、論理サーバーだったらfalseを返す。これは、物理サーバーでは常にfalseを返すため、物理クライアントの論理サーバーと値が被っている。原則、それが物理サーバーか論理サーバーか、この値からではわからない。
この真偽値の使いどころは、ゲームのルールやそのほかの仕組みを実行したいときである。例えば、

  • あるブロックに触れている間は、ずっとダメージを受け続ける
  • ある機械に土を入れると、それをダイヤモンドに変える

などである。これらはworld.isRemoteの値がfalseの時に実行するべきだ。これらを論理クライアントで実行してしまうと、論理サーバーとの整合性が取れなくなり、軽いバグの場合、モブのゴースト現象や体力の不一致などが発生する。重いバグの場合はゲームがクラッシュしてしまうこともある。

getEffectiveSide

FMLCommonHandler.getEffectiveSide()は何らかの理由によって、world.isRemoteが使えない時に使われる。これはどっちのサイドかを、推測する。なぜ推測かというと、これはスレッドの名前(Server ThreadもしくはClient Thread)から、どちらのサイドかを判断するからだ。worldが使用可能の時は、できるだけworld.isRemoteを使うようにして、これはその方法が使えないときの代替手段として使うべきだ。

解決

なるほど、どうやらワールドのブロックなどの管理をしているのは論理サーバーらしいから、論理クライアントと論理サーバーでworld.createExplosion()を実行してしまうと、サーバーにあるブロック情報とクライアントにあるブロック情報が食い違ってしまうから、ゴーストブロック現象が起こるらしい。爆発で破壊するブロックはランダムで決めているから、クライアントでは破壊したことになっているブロックもサーバーでは爆発を免れているかもしれない。ここで、存在しないブロックに対する当たり判定が発生していたのだ。よって、この問題の解決方法は、

if (!world.isRemote)
    world.createExplosion(...);

となる。当たり判定やゴーストエンティティで悩んでいるModderは論理サーバーのみ、論理クライアントのみでの実行を一回試してみたら幸せになれるだろう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MacでAWS Lambda関数(java)を作るまで

MacでAWS Lambda関数(java)を作るまで

思いつきで使った事のないMacBookAirを買い、思いつきでAWS Lambda関数を作ろうとしたものの、慣れないJavaScriptで書くのはストレスなので、慣れたJavaで作ろうとしたところ、すんなりといかなかったので残しておきます。

前提

  • 2019.08.03現在のAWS Lambdaのランタイムは、ava-1.8.0-openjdk-Amazon linuxです
  • homebrewというものがインストールされていること
  • anyenvというものがインストールされていること

javaのインストール

java8の検索

Macにjavaをインストールします。lambdaランタイムがopenjdk8なのでhomebrewでopenjdkがインストールできるのか探します。

# おまじない
$ brew tap caskroom/versions
# openjdkを検索
$ brew search openjdk
==> Casks
adoptopenjdk                             adoptopenjdk8

openjdkのインストール

「adoptopenjdk8」という、いかにもjava8らしきものがあったのでこれをインストールします。途中でパスワードを聞かれますのでOSのパスワードを入力します。

# openjdk ver8をinstall
$ brew cask install adoptopenjdk8
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/cask).
No changes to formulae.

==> Satisfying dependencies
==> Downloading https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/downl
==> Downloading from https://github-production-release-asset-2e65be.s3.amazonaws
######################################################################## 100.0%
==> Verifying SHA-256 checksum for Cask 'adoptopenjdk8'.
==> Installing Cask adoptopenjdk8
==> Running installer for adoptopenjdk8; your password may be necessary.
==> Package installers may write to any location; options such as --appdir are i
Password: #osのパスワード入力
installer: Package name is AdoptOpenJDK
installer: Installing at base path /
installer: The install was successful.
?  adoptopenjdk8 was successfully installed!

javaバージョンの確認

macで有効になっているjavaバージョンを確認してみます。

$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.222-b10, mixed mode)

jenvのインストール

jenvはjavaのバージョンをフォルダ毎に指定したりとかいい感じにやってくれるものです。
ReadMeに沿ってインストールします。

$ anyenv install jenv

jenvにJavaを追加する

jenv経由でjavaをインストールできないので、インストールされたjavaをjenvに教えてあげる必要があります。

$ jenv add $(/usr/libexec/java_home)
openjdk64-1.8.0.222 added
1.8.0.222 added
1.8 added

javaバージョンの確認

jenvが扱えるjavaバージョンの確認

$ jenv versions
* system (set by /Users/xxx/.anyenv/envs/jenv/version)
  1.8
  1.8.0.222
  openjdk64-1.8.0.222

Mavenのインストール

ライブラリの定義やビルドをしやすくしたいのでMavenも入れます。

Mavenの検索

Mavenもhomebrewで入れられました。

$ brew search maven
==> Formulae
maven   maven-completion   maven-shell   maven@3.2   maven@3.3   maven@3.5

==> Casks
mavensmate   homebrew/cask-fonts/font-maven-pro

Mavenのインストール

特にバージョンにはこだわらないので最新をインストール。

$ brew install maven
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 2 taps (homebrew/cask and caskroom/versions).
No changes to formulae.

==> Downloading https://www.apache.org/dyn/closer.cgi?path=maven/maven-3/3.6.1/binaries/apache-maven-3.6.1-bin.tar.gz
==> Downloading from https://www-eu.apache.org/dist/maven/maven-3/3.6.1/binaries/apache-maven-3.6.1-bin.tar.gz
######################################################################## 100.0%
?  /usr/local/Cellar/maven/3.6.1: 79 files, 10.2MB, built in 30 seconds

Visual Studio Codeの設定

Eclipseでも良いのですが、軽いと噂のVisual Studio Codeを使ってみたいのでインストール。

Visual Studio Codeのインストール

Download Visual Studio Codeからダウンロードしてインストールしてください。

VS CodeにJavaの拡張機能を追加

こちらに纏まっていますので、こちらを参照して「Java Extension Pack」の追加を行って下さい。
「java開発環境をvisual-studio-code-で整える」
※jenvのおかげかJAVA_HOMEの設定はせずとも大丈夫でした。

Javaの実装 & AWS Lambda関数にデプロイ

こちらに丁寧に纏まっていますので、こちらを参照して下さい。
「いまからはじめるJavaでAWS Lambda(ラムダ) 前編」

AWS API Gateway

パブリックに呼び出せるように、AWS LambdaのトリガーをAPI Gatewayにします。
が、ここで大ハマりしました。
上記までで、AWS Lambdaのテストはうまくいくのですが、API Gatewayを作ってテストを実行すると502でエラーとなるのです。

結論から言うと「API Gateway」の「統合リクエスト」の設定が初期値だとうまくいきませんでした。

AWS Lambdaにトリガーを設定

ここは素直に「+」ボタンでトリガーを追加して、下記のように選択します。

  1. API Gateway を選択
  2. API:素直に「新しいAPIを作成」
  3. セキュリティ:後からでも変更できるので、テストのしやすさを考えて「オープン」

スクリーンショット 2019-08-04 18.24.38.png

スクリーンショット 2019-08-04 18.47.26.png

統合リクエストの設定を変える

AWS Lambda コンソールにて、追加れたメソッドの「統合リクエスト」を選択します。

スクリーンショット 2019-08-04 18.50.52.png

ここが大切です。
この中の「Lambdaプロキシ統合の使用」にチェックが入っているので、このチェックを外します。

スクリーンショット 2019-08-04 18.28.09.png

怖いインフォメーションも無視してOKを押します。
スクリーンショット 2019-08-04 18.51.53.png

このチェックを外す事で、うまくいくようになりました。

まとめ

API GatewayからLambdaのJava を呼び出すところで、リクエストBODYのjsonの内容をJavaの入力パラメータのPOJOに値を詰める処理が動くわけですが、「Lambdaプロキシ統合の使用」にチェックが入っているとどうもここがうまくいきません。

推測するに、API Gatewayでは、リクエストの情報と一緒にAWSのメタな情報もセットで持ち回っており、「Lambdaプロキシ統合の使用」にチェックが入っていると、メタな情報もLambdaに渡せる反面、Lambda側でもそのつもりで受け取る実装にしておかないとダメで、今回の実装はjsonの内容しか受け取るようにしていなかったので失敗していたようです。

「Lambdaプロキシ統合の使用」のチェックを外すとリクエストBODYのみLambdaに渡すようになり、POJOで受け取れるようになりました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java学習メモ(メソッド)

Java Silverの勉強を始めたので、自分の忘備録としてUPします。
ざっくりとしたメモなので、詳細は記載してません。

メソッド定義における戻り値型について。

int型を戻すメソッド
int method(int num){
return num * 5;
}

戻り値を返さない場合
void method(int num){
System.out.println(num);
}

戻り値を返さないのに戻り値型を宣言するとコンパイルエラーになる。
また、宣言した戻り値型と異なる型で返そうとしてもコンパイルエラーになる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java学習メモ (while文、do-while文)

Java Silverの勉強を始めたので、自分の忘備録としてUPします。
ざっくりとしたメモなので、詳細は記載してません。

while文、do-while文でも{}を省略することが可能である。
しかし、{}を省略した場合、繰り返されるのは1文だけなので注意すること。
以下の例文だと繰り返されるのは「System.out.println("1文目");」のみである。

int cnt = 0;
while(cnt++ < 10)
System.out.println("1文目");
  System.out.println("2文目");

1行ではなく、1文である点も要注意。
改行していなくても「;」で区切っていれば1文目しか繰り返しはされない。

また、{}を省略した際に2文以上記述するとコンパイルエラーになる。
int cnt = 0;
do
System.out.println("1文目");
  System.out.println("2文目");
while(cnt++ < 10);

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

大先輩に教えてもらったシステム開発の敷居を下げる一言

はじめに

 本記事は、自分が設計及びプログラミングに向いていないと思っていた時に
 大先輩に教えてもらった敷居を下げる一言を紹介します。
 同じように、プログラマーになったはいいけど、向いていないと思っている方の救いに
 なれば幸いです。

プログラムなんて、INとOUTがあるだけだ。

 表題の言葉を投げかけてもらえました。
 自分はこの時割とコピペで作業を進めており、初めて設計を任されたときに
 全然できませんでした。
 この言葉のおかげで、少しずつ書けるようになってきたと思っています。
 よく考えればその通りで
 主要なサービスは以下のように考えることができます。
 (筆者の未経験分野は誤りがあるかもしれません)

サービス In Out
Webシステム 画面表示のプログラム Web上の画面
データ分析 データ 分析結果
機械学習 学習ロジック、学習データ 学習結果
RPA 規則 規則の自動化
組み込みシステム 制御プログラム ハードウェア

じゃあ、設計におけるINとOUTの考え方って?

 設計におけるINとOUTは、人によってぶれることが少ないです。
 私は大きくは
 IN:要件(あれがしたい、これがしたい)と前提条件
 OUT:要件を満たすこと

と考えておりますが、だいたいの場合こうなるのではないでしょうか?

 これを以下の観点で細分化することが、「INがあってOUTがあるだけ」の状態に持っていく近道だと思っています。
 ・自分の技術レベル
 ・チームの技術レベルや意識
 ・チーム(個人)で使用している技術
 ・今後の方針
 ・納期

 実際に、以下の例で話させていただきたいです。

あなたは1年目のjavaプログラマです。
きまぐれなお客様に、システムを作成してほしいと依頼を受けました。
お客様の望みは、「100までの数字を「3で割り切れるならFizz」「5で割り切れるならBuzz」「3と5で割り切れるならFizzBuzz」とコンソールに出してほしい。
1日でやってね。あとJavaでお願い。
との事です。

さて、この例を、INとOUTがあるだけの状態に持っていくには、どうすればいいでしょうか?
その為には、この順で思考を整理していきましょう。
 ・OUT
 ・IN
 ・納期
 ・今後の方針
以下で、上記の順に例題を解いていきます。

まずOUTにあたる部分は
「0~100を「3で割り切れるならFizz」「5で割り切れるならBuzz」「3と5で割り切れるならFizzBuzz」をコンソールに出力すること。」です。(以下FizzBuzzと記述)

なぜOUTから考えるかですが、当然OUTが伴わないと、時間をかけて作成したシステムが無駄になるからです。
どんなに素晴らしいロジックでも、OUTを満たせなければお客様からは見えないです。
なので、最優先にOUTを考えましょう。

また、OUTを考えた結果とても無理難題であることが分かった場合は、お客様との交渉が必要ですが、それはまた別の機会に・・・

次に考えるのは、INにあたる部分です。
今回のINはOUTと同様ですが、前提条件にあたる部分がJavaでやってね
の部分といえます。
ですので、
IN:JavaでFizzBuzzを1日でやってほしい
OUT:INを滞りなく終わらせる。

となります。

次に考えるのは「納期」です。
今回納期にあたる部分は「1日でお願い」の箇所です。
つまり、1日以内です。

納期をIN/OUTの後に考える理由は、交渉のタイミングを実際に作業に入る前にする為です。
このタイミングですぐに無理。と言えれば、お客様や同じチームのリーダーの説得が楽になります。
今回の例題では、1年目なのでFizzBuzzを余裕で納期通りにクリアする能力を有していると考えます。
例:別の技術レベルを持った人と担当替え、納期を遅らせる等

最後に今後の方針ですが、

今後運用していく上で、FizzBuzzを使いたい機能が出てくるのか
それともFizzBuzzは、今回限りで再利用することはないのか
200までの数値でFizzBuzzをしたい、といった変更はないか
といったことを考えていきます。

今回の例では特にそのような記述は見当たりませんが 
気まぐれなお客様ということは最後の

200までの数値でFizzBuzzをしたい、といった変更はないか

という部分に該当する可能性は大いにありますね。

しかし、ここで考えなくてはならないのは納期です。
自分ないしチームでやって、気まぐれという点に対処する時間がとれるのかを考えましょう。

さて、ここまでで一通り細分化ができました。

最後に、ここまでの考えを整理すると

IN:FizzBuzzを1日で作成してほしい。言語はJava
OUT:INを滞りなく実行する。
納期:余裕で達成できそう。
今後の方針:お客様は気まぐれなので、変更の可能性がある。

となります。

INとOUTを確定させるなら、残りの未確定部分は
・今後の方針をOUTに組み込むか
といった観点です。

今回は納期に余裕でクリアできる力を持っているので
組み込んでおく方がよいでしょう。

これで完成したIN/OUTは
IN:1日以内で、FizzBuzzを作る
OUT:INを満たしつつ今後の変更に耐えられるFizzBuzzを作成する。

となります。
このIN/OUTを実現する設計は、何も考えずに設計をするよりも簡単ではないでしょうか?

それでは、次は実際にプログラミングに入っていきます。

プログラムにおけるIN/OUTは?

プログラムにおけるIN/OUTはこのようになるのではないでしょうか
 IN:前提となるデータや条件
 OUT:実行の結果(返却値や成果物)

それでは、先ほどのFizzBuzzに倣って考えていきます。
プログラムにおけるIN、OUTの考え方は
・INの取得元
・OUTの出し方
・INをOUTにする為の処理

の観点です。
1つずつFizzBuzzに沿って実装していきましょう。

まず・INの取得元ですが
今回の設計におけるINは

nまでの数値

です。
取得元は特に書いていませんので、自由にやってよいでしょう。
例えば、nに入る値が可変であることを考えると、以下のように引数で受け取る形がよいでしょうか。
(この段階ではコンパイルエラーとなるコードです。)

FizzBuzz.java
// 引数としてtargetNum=FizzBuzz対象の任意の数値を受け取る。
public doFizzBuzz(int targetNum)

次に考えるのは、OUTの出し方です。
今回はコンソールに出力すると指定を受けていますが
メソッド内で完結か、メソッドからの返却値を出力か、といったことが考えられます。
今回は、メソッド内で完結する方式で作成していきます。

FizzBuzz.java
// 戻り値を返さないvoidを宣言。このメソッドで出力する。
public void doFizzBuzz(int targetNum){
 System.out.println("Fizz");
 System.out.println("Buzz");
 System.out.println("FizzBuzz");

}

次に考えるのは、プログラムにおける醍醐味でもあるINをOUTにするための処理です。
この部分は実装者の裁量が最も大きく、慣れてくるとやりがいがあります。

さて、今回は
 ・3で割り切れる数値は「Fizz」
 ・5で割り切れる数値は「Buzz」
 ・3と5で割り切れる数値は「FizzBuzz」という要件です。
これを実行する方法は、様々ですが、
今回はif-else ifで実施します。

まずFizzBuzzの「nで割り切れたら〇〇」の部分です。
確実に必要な数値は3と5であることは間違いなさそうです。
しかし、気まぐれなお客様なのでもしかしたら3と5以外でも割ってみたいというかもしれませんね。
ですが、そこを考慮すると納期が延びる可能性があるので、今回は定数として定義しておきましょう。

FizzBuzz.java
// 定数として定義する。これらをメソッド内で使用することで変更が容易。
public static final int FIZZ_VAL = 3;

public static final int BUZZ_VAL = 5;


そしていよいよ実際に割り算を行う処理を考えていきます。
今回は、nまでの数値が何で割り切れたかを知るために3,5,3と5でそれぞれ条件分岐を行う必要があります。
今回は、単純にif-else ifで条件分岐をしていきますが、
3と5で割り切れたらを先頭にしないと要件を満たせません。
ですので、以下のようにソースを記述します。

FizzBuzz.java
    public static final int FIZZ_VAL = 3;

    public static final int BUZZ_VAL = 5;

    public void doFizzBuzz(int targetNum) {
        // targetNum回ループ、iをインクリメントしてnまでの数値を実現
        for(int i = 0; i <= targetNum; i++) {
           // 最初にFizzBuzzの条件にかかるかチェック
            if(i % FIZZ_VAL == 0 && i % BUZZ_VAL == 0) {
                System.out.println("FizzBuzz");
           // 次はFizzの条件に引っかかるかチェック
            } else if(i % FIZZ_VAL == 0) {
                System.out.println("Fizz");
           // 次はBuzzの条件に引っかかるかチェック
            } else if(i % BUZZ_VAL == 0) {
                System.out.println("Buzz");
          // どれにもかからない数値はそのまま出力。
            } else {
                System.out.println(i);
            }
        }
    }

ここまでFizzBuzzが完成しました。
ポイントは、OUTを実現する方法をINから細分化していくことです。
なぜINからかというと、INにあたる前提条件は個人の裁量が少なく、
そこで決められたことで実施する方法をとらざるを得ないことが多いからです。

最後に、FizzBuzzの完全版を載せておきます。

FizzBuzz.java
public class FizzBuzz {

    // 定数定義、割り算に使用する数値を定数化
    public static final int FIZZ_VAL = 3;

    public static final int BUZZ_VAL = 5;


    // Javaで実施する。のでエントリーポイントであるメインメソッドを記述
    public static void main(String[] args) {
        /*
         *  staticメソッドであるmain()から
         *  インスタンスメソッドであるdoFizzBuzzを呼び出すために
         *  インスタンス化
         */
        FizzBuzz fizzBuzz = new FizzBuzz();
         fizzBuzz.doFizzBuzz(100);
    }

    // FizzBuzz本体、if-else if-elseを用いてFizzBuzzの判定を行う。
    public void doFizzBuzz(int targetNum) {
        for(int i = 0; i <= targetNum; ++i){
            if(i % FIZZ_VAL == 0 && i % BUZZ_VAL == 0){
                System.out.println("FizzBuzz");
            }else if(i % FIZZ_VAL == 0){
                System.out.println("Fizz");
            }else if(i % BUZZ_VAL == 0){
                System.out.println("Buzz");
            }else{
                System.out.println(i);
            }
        }
    }
}

おわりに

 ここまでの長文にお付き合いいただきありがとうございました
 同じように苦しい思いをして、今はシステム開発を楽しんでいる私のように
 少しでも楽になれば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

大先輩に教えてもらったシステム開発のハードルを下げる一言

はじめに

 本記事は、自分が設計及びプログラミングに向いていないと思っていた時に
 大先輩に教えてもらったハードルを下げる一言を紹介します。
 同じように、プログラマーになったはいいけど、向いていないと思っている方の救いに
 なれば幸いです。

プログラムなんて、INとOUTがあるだけだ。

 表題の言葉を投げかけてもらえました。
 自分はこの時割とコピペで作業を進めており、初めて設計を任されたときに
 全然できませんでした。
 この言葉のおかげで、少しずつ書けるようになってきたと思っています。
 よく考えればその通りで
 主要なサービスは以下のように考えることができます。
 (筆者の未経験分野は誤りがあるかもしれません)

サービス In Out
Webシステム 画面表示のプログラム Web上の画面
データ分析 データ 分析結果
機械学習 学習ロジック、学習データ 学習結果
RPA 規則 規則の自動化
組み込みシステム 制御プログラム ハードウェア

じゃあ、設計におけるINとOUTの考え方って?

 設計におけるINとOUTは、人によってぶれることが少ないです。
 私は大きくは
 IN:要件(あれがしたい、これがしたい)と前提条件
 OUT:要件を満たすこと

と考えておりますが、だいたいの場合こうなるのではないでしょうか?

 これを以下の観点で細分化することが、「INがあってOUTがあるだけ」の状態に持っていく近道だと思っています。
 ・自分の技術レベル
 ・チームの技術レベルや意識
 ・チーム(個人)で使用している技術
 ・今後の方針
 ・納期

 実際に、以下の例で話させていただきたいです。

あなたは1年目のjavaプログラマです。
きまぐれなお客様に、システムを作成してほしいと依頼を受けました。
お客様の望みは、「100までの数字を「3で割り切れるならFizz」「5で割り切れるならBuzz」「3と5で割り切れるならFizzBuzz」とコンソールに出してほしい。
1日でやってね。あとJavaでお願い。
との事です。

さて、この例を、INとOUTがあるだけの状態に持っていくには、どうすればいいでしょうか?
その為には、この順で思考を整理していきましょう。
 ・OUT
 ・IN
 ・納期
 ・今後の方針
以下で、上記の順に例題を解いていきます。

まずOUTにあたる部分は
「0~100を「3で割り切れるならFizz」「5で割り切れるならBuzz」「3と5で割り切れるならFizzBuzz」をコンソールに出力すること。」です。(以下FizzBuzzと記述)

なぜOUTから考えるかですが、当然OUTが伴わないと、時間をかけて作成したシステムが無駄になるからです。
どんなに素晴らしいロジックでも、OUTを満たせなければお客様からは見えないです。
なので、最優先にOUTを考えましょう。

また、OUTを考えた結果とても無理難題であることが分かった場合は、お客様との交渉が必要ですが、それはまた別の機会に・・・

次に考えるのは、INにあたる部分です。
今回のINはOUTと同様ですが、前提条件にあたる部分がJavaでやってね
の部分といえます。
ですので、
IN:JavaでFizzBuzzを1日でやってほしい
OUT:INを滞りなく終わらせる。

となります。

次に考えるのは「納期」です。
今回納期にあたる部分は「1日でお願い」の箇所です。
つまり、1日以内です。

納期をIN/OUTの後に考える理由は、交渉のタイミングを実際に作業に入る前にする為です。
このタイミングですぐに無理。と言えれば、お客様や同じチームのリーダーの説得が楽になります。
今回の例題では、1年目なのでFizzBuzzを余裕で納期通りにクリアする能力を有していると考えます。
例:別の技術レベルを持った人と担当替え、納期を遅らせる等

最後に今後の方針ですが、

今後運用していく上で、FizzBuzzを使いたい機能が出てくるのか
それともFizzBuzzは、今回限りで再利用することはないのか
200までの数値でFizzBuzzをしたい、といった変更はないか
といったことを考えていきます。

今回の例では特にそのような記述は見当たりませんが 
気まぐれなお客様ということは最後の

200までの数値でFizzBuzzをしたい、といった変更はないか

という部分に該当する可能性は大いにありますね。

しかし、ここで考えなくてはならないのは納期です。
自分ないしチームでやって、気まぐれという点に対処する時間がとれるのかを考えましょう。

さて、ここまでで一通り細分化ができました。

最後に、ここまでの考えを整理すると

IN:FizzBuzzを1日で作成してほしい。言語はJava
OUT:INを滞りなく実行する。
納期:余裕で達成できそう。
今後の方針:お客様は気まぐれなので、変更の可能性がある。

となります。

INとOUTを確定させるなら、残りの未確定部分は
・今後の方針をOUTに組み込むか
といった観点です。

今回は納期に余裕でクリアできる力を持っているので
組み込んでおく方がよいでしょう。

これで完成したIN/OUTは
IN:1日以内で、FizzBuzzを作る
OUT:INを満たしつつ今後の変更に耐えられるFizzBuzzを作成する。

となります。
このIN/OUTを実現する設計は、何も考えずに設計をするよりも簡単ではないでしょうか?

それでは、次は実際にプログラミングに入っていきます。

プログラムにおけるIN/OUTは?

プログラムにおけるIN/OUTはこのようになるのではないでしょうか
 IN:前提となるデータや条件
 OUT:実行の結果(返却値や成果物)

それでは、先ほどのFizzBuzzに倣って考えていきます。
プログラムにおけるIN、OUTの考え方は
・INの取得元
・OUTの出し方
・INをOUTにする為の処理

の観点です。
1つずつFizzBuzzに沿って実装していきましょう。

まず・INの取得元ですが
今回の設計におけるINは

nまでの数値

です。
取得元は特に書いていませんので、自由にやってよいでしょう。
例えば、nに入る値が可変であることを考えると、以下のように引数で受け取る形がよいでしょうか。
(この段階ではコンパイルエラーとなるコードです。)

FizzBuzz.java
// 引数としてtargetNum=FizzBuzz対象の任意の数値を受け取る。
public doFizzBuzz(int targetNum)

次に考えるのは、OUTの出し方です。
今回はコンソールに出力すると指定を受けていますが
メソッド内で完結か、メソッドからの返却値を出力か、といったことが考えられます。
今回は、メソッド内で完結する方式で作成していきます。

FizzBuzz.java
// 戻り値を返さないvoidを宣言。このメソッドで出力する。
public void doFizzBuzz(int targetNum){
 System.out.println("Fizz");
 System.out.println("Buzz");
 System.out.println("FizzBuzz");

}

次に考えるのは、プログラムにおける醍醐味でもあるINをOUTにするための処理です。
この部分は実装者の裁量が最も大きく、慣れてくるとやりがいがあります。

さて、今回は
 ・3で割り切れる数値は「Fizz」
 ・5で割り切れる数値は「Buzz」
 ・3と5で割り切れる数値は「FizzBuzz」という要件です。
これを実行する方法は、様々ですが、
今回はif-else ifで実施します。

まずFizzBuzzの「nで割り切れたら〇〇」の部分です。
確実に必要な数値は3と5であることは間違いなさそうです。
しかし、気まぐれなお客様なのでもしかしたら3と5以外でも割ってみたいというかもしれませんね。
ですが、そこを考慮すると納期が延びる可能性があるので、今回は定数として定義しておきましょう。

FizzBuzz.java
// 定数として定義する。これらをメソッド内で使用することで変更が容易。
public static final int FIZZ_VAL = 3;

public static final int BUZZ_VAL = 5;


そしていよいよ実際に割り算を行う処理を考えていきます。
今回は、nまでの数値が何で割り切れたかを知るために3,5,3と5でそれぞれ条件分岐を行う必要があります。
今回は、単純にif-else ifで条件分岐をしていきますが、
3と5で割り切れたらを先頭にしないと要件を満たせません。
ですので、以下のようにソースを記述します。

FizzBuzz.java
    public static final int FIZZ_VAL = 3;

    public static final int BUZZ_VAL = 5;

    public void doFizzBuzz(int targetNum) {
        // targetNum回ループ、iをインクリメントしてnまでの数値を実現
        for(int i = 0; i <= targetNum; i++) {
           // 最初にFizzBuzzの条件にかかるかチェック
            if(i % FIZZ_VAL == 0 && i % BUZZ_VAL == 0) {
                System.out.println("FizzBuzz");
           // 次はFizzの条件に引っかかるかチェック
            } else if(i % FIZZ_VAL == 0) {
                System.out.println("Fizz");
           // 次はBuzzの条件に引っかかるかチェック
            } else if(i % BUZZ_VAL == 0) {
                System.out.println("Buzz");
          // どれにもかからない数値はそのまま出力。
            } else {
                System.out.println(i);
            }
        }
    }

ここまでFizzBuzzが完成しました。
ポイントは、OUTを実現する方法をINから細分化していくことです。
なぜINからかというと、INにあたる前提条件は個人の裁量が少なく、
そこで決められたことで実施する方法をとらざるを得ないことが多いからです。

最後に、FizzBuzzの完全版を載せておきます。

FizzBuzz.java
public class FizzBuzz {

    // 定数定義、割り算に使用する数値を定数化
    public static final int FIZZ_VAL = 3;

    public static final int BUZZ_VAL = 5;


    // Javaで実施する。のでエントリーポイントであるメインメソッドを記述
    public static void main(String[] args) {
        /*
         *  staticメソッドであるmain()から
         *  インスタンスメソッドであるdoFizzBuzzを呼び出すために
         *  インスタンス化
         */
        FizzBuzz fizzBuzz = new FizzBuzz();
         fizzBuzz.doFizzBuzz(100);
    }

    // FizzBuzz本体、if-else if-elseを用いてFizzBuzzの判定を行う。
    public void doFizzBuzz(int targetNum) {
        for(int i = 0; i <= targetNum; ++i){
            if(i % FIZZ_VAL == 0 && i % BUZZ_VAL == 0){
                System.out.println("FizzBuzz");
            }else if(i % FIZZ_VAL == 0){
                System.out.println("Fizz");
            }else if(i % BUZZ_VAL == 0){
                System.out.println("Buzz");
            }else{
                System.out.println(i);
            }
        }
    }
}

おわりに

 ここまでの長文にお付き合いいただきありがとうございました
 同じように苦しい思いをして、今はシステム開発を楽しんでいる私のように
 少しでも楽になれば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Mockito+PowerMockチートシート

はじめに

Javaのユニットテストで Mockito + PowerMock でモックする時に、よく使いそうなものをできる限り簡潔にまとめてみます。(随時追記していく予定です)

目次

MockitoとPowerMockを導入する

Gradleの場合、build.gradleに以下の依存関係を追加します。

build.gradle
dependencies {
    testImplementation 'junit:junit:4.12'
    testImplementation "org.mockito:mockito-core:2.28.+"
    testImplementation 'org.powermock:powermock-module-junit4:2.0.2'
    testImplementation 'org.powermock:powermock-api-mockito2:2.0.2'
}

staticメソッドをモック化する

以下のメソッドをテストする場合にメソッドから呼び出しているstaticメソッド「ExampleDBA.findAll()」をモック化してみます。

テスト対象クラス
import java.util.List;

public class ExampleLogic {
    public Integer countExamples() {
        List<ExampleDTO> list = ExampleDBA.findAll();
        return list.size();
    }
}
テストクラス
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.powermock.api.mockito.PowerMockito.when;

import java.util.Arrays;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class) //(1)
@PrepareForTest({ ExampleDBA.class }) //(2)
public class ExampleLogicTest {

    ExampleLogic logic = new ExampleLogic();

    @Before
    public void setUp() throws Exception {
        PowerMockito.mockStatic(ExampleDBA.class); //(3)
    }

    @Test
    public void countExamples() {
        List<ExampleDTO> result = Arrays.asList(new ExampleDTO());
        when(ExampleDBA.findAll()).thenReturn(result); //(4)
        assertThat(logic.countExamples(), equalTo(1));
    }
}

(1) PowerMockを使う場合に必要なおまじないです。
(2) モック化するstaticメソッドを持つクラスを指定します。
(3) モック化するstaticメソッドを持つクラスを指定します。
(4) staticメソッドが実行された場合の戻り値を指定します。

newされているインスタンスをモック化する

テスト対象クラス
public class ExampleService {
    public Integer count() {
        ExampleLogic logic = new ExampleLogic();
        return logic.countExamples();
    }
}
テストクラス
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.mockito.PowerMockito.whenNew;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class) //(1)
@PrepareForTest({ ExampleService.class }) //(2)
public class ExampleServiceTest {

    ExampleService service = new ExampleService(); //(3)

    @Test
    public void count() throws Exception {
        ExampleLogic logic = mock(ExampleLogic.class); //(4)
        whenNew(ExampleLogic.class).withNoArguments().thenReturn(logic); //(5)
        when(logic.countExamples()).thenReturn(0); //(6)

        assertThat(service.count(), equalTo(0));
    }
}

(1) PowerMockを使う場合に必要なおまじないです。
(2) テスト対象クラスを指定します。
(3) テスト対象クラスのインスタンスを生成します。
(4) モックオブジェクトを作成します。
(5) newされた時にモックオブジェクトを返すように設定します。
(6) モックオブジェクトのメソッドが呼ばれた際の戻り値を設定します。
(*) モック化対象のオブジェクトをnewする前に(4)〜(6)は実施する必要があります。
 例えば、ExampleServiceのコンストラクタでExampleLogicをnewしている場合、
 ExampleServiceは(6)の後で(3)する必要があります。

一部のメソッドをモック化する

テスト対象クラス
public class ExampleLogic2 {
    private String privateMethod() {
        return "abc";
    }
    public String publicMethod() {
        String str = privateMethod();
        return str.toUpperCase();
    }
}
テストクラス
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class) //(1)
@PrepareForTest(ExampleLogic2.class) //(2)
public class ExampleLogicTest2 {

    @Test
    public void publicMethod() throws Exception {
        ExampleLogic2 logic = spy(new ExampleLogic2()); //(3)
        when(logic, "privateMethod").thenReturn("str"); //(4)
        assertThat(logic.publicMethod(), equalTo("STR"));
    }
}

(1) PowerMockを使う場合に必要なおまじないです。
(2) テスト対象クラスを指定します。
(3) 一部のメソッドをモック化するためテスト対象クラスをnewしてspyを呼び出します。
(4) モック化するメソッド(この例ではprivate)の戻り値を設定します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む