宿題やりなよー(๑˘・з・˘)エーーーーヤダーー

父「宿題やりなよー」

(๑˘・з・˘)エーーーーヤダーーーーヤダヤダーーーー

って顔になるときは、こんな風に遊んだりする。

いっつもじゃないよ?気が向いたときだけ。

ちょっと前にお掃除の話を書いたけど、うちでは宿題はそれよりも難易度高めかな。

bufferings.hatenablog.com

アホな生徒になる

まずはアホな生徒になる。

父「宿題見せて?えー。こんなんめっちゃ簡単やん!30÷3=33やろ!こんなんも分からんの?」←明らかに間違えていることが分かるようにする

(๑˘・з・˘)「はぁ・・・。なに足してんの?30÷3=10だよ」

父「え?なんで30を3で割ったら・・・あ、そうか20かな?」←説明してもらえるように、もういっかい間違える

(๑˘・з・˘)「そうじゃないでしょ。30を3で割るってことは、3つに分けるってことなの。だから10でしょ」

父「先生。分かりません。もうちょっと分かりやすく教えてください。」←どこまで分かってるのかなーって思って

(๑˘・з・˘)「もう・・・。30個のドングリがあって、それをパパとママと私で分けると、一人10個でしょ」

父「あー分かった、なるほど!すごいね!」←褒める

( ー`дー´)「次のこの問題は、こういう風に解くんだよ」←可愛すぎて父はもうだめ

ライバルになる

娘がちょっとやる気を出したところで、ライバルになって宿題を一緒に始める。

父「完全に理解した!面白いね!お父さんの方が先に全部解くわ!」

( ー`дー´)「負けないんだから!」←可愛すぎて父はもうだめ

同級生になる

分からない問題があるときには同級生になる。

(๑˘・з・˘)「・・・」

父「どしたん?あ、この問題難しいね。どうやって考えたらいいのかなぁ。こういうのはどう?」←ちょっと間違えておく

(๑˘・з・˘)「あぁ、確かに。でも、・・・あ、こうじゃない?」

父「あー。そっか。いや、お父さんもそう思ってたけどね!」←ふつうに負けず嫌い気分で言ってしまう

( ー`дー´)「私が言ってから気づいたでしょ!」←可愛すぎて父はもうだめ

ライバルになる

間違えてるところを見つけたら「そこ間違えてるよ」って言うと怒るので、ライバルになって

父「そこ、お父さんと答え違うけど、お父さんの方が正しいと思う」

(๑˘・з・˘)「え?でも、これは二等辺三角形でしょ?」

父「ぷぷぷ・・・おしえなーい」

(๑˘・з・˘)「あー!!!もういっこも同じ長さだから正三角形だ!!!」

アホな生徒になる

面白い問題があったときは、アホな生徒になって楽しむ。

父「これ・・・『このときの少年の気持ちを答えなさい』ってもしかしたら『コオロギって地球上に何匹くらいいるのかなぁ?』って思ってるかもしれないじゃん?」

(๑˘・з・˘)「いや、そうかもしれないけど、この問題だとたぶんこういう感じだよ」

父「えー!そんなの本人しか分からんやん!『アジサイの写真が見たいなぁ』とかかもしれんやん!」

(๑˘・з・˘)「そんなこと考えてるから、国語の成績悪かったんでしょ?ちょっと待ってね。(図鑑を持ってくる)アジサイの写真なら・・・ほらこれだよ」

父「そっかー。ありがとう!」

(๑˘・з・˘)「いえいえー。でも、そういうのも良いと思うよ」←うえからかわいい。

飽きる前に休憩

父「・・・疲れた。もう十分がんばったよ。ここまででやめようよ・・・。明日宿題忘れててもバレないよ・・・。」←半分本気でそう思ってる

(๑˘・з・˘)「もう・・・大人なんだからそういうこと言わずに最後までやりなさいよ。あとちょっとでしょ」

父「えー。じゃ、ちょっと休憩しよう?」

(๑˘・з・˘)「じゃ、5分だけね」

父「わーい」

最後はお母さんに褒めてもらう

父「うぉー!全部終わった!がんばった!お母さんに褒めてもらおー!」←立ち上がる

ヽ(=´▽`=)ノ「ママー!!終わったよーーー!!!!」←全力ダッシュ

まとめ

こんな感じ

  • アホな生徒になって娘に先生をやってもらう
  • ライバルになって競争する
  • 同級生になって一緒に考える
  • ライバルになって間違いを指摘する
  • アホな生徒になって勉強を楽しむ
  • 飽きる前に休憩する
  • お母さんに褒めてもらう

親から子供に対して「やらせる」ってよりも「一緒に考えることを楽しむ」って感じかな。勉強は楽しい。

お父さんは時間の感覚をみにつけたいぞ!

時間の感覚

娘1は時間に合わせて行動するのが苦手。

例えば、8時に家を出るから7時半には準備を始めなきゃいけない。ということが苦手。

妻さんが「どうしたらいいと思う?」って言うので

僕「それ僕のことやで」

妻さん「?」

ふむ・・・

僕「みんな集まってー!」

お父さんの悩み

娘たちよ。お父さん、実は悩みがある。

お父さん、時間に合わせて行動するのが苦手なんよ。娘1はどうしたらいいと思う?

娘1「うーん。私も苦手だからなー。でも、娘2はママに似て得意だよね?」

娘2「うん!わたしはとくいだよ」

娘1「あ、いいこと思いついた。こういうのはどう?娘2に時間を教えてもらうの」

お?じゃあ、娘2はおでかけのときお父さんに「そろそろ顔を洗う時間だよ!」って教えてくれるの?

娘2「いいよ!」

(∩´∀`)∩ワーイ

今日は習い事

娘1は今日は習い事で13時に家を出ないといけない。

いつもなら、妻さんに「そろそろ服着替えないと間に合わないよ?」って言われてるのだけど。

娘2「おねえちゃん、そろそろきがえるじかんだから、おようふくもってくるね!」

娘1「あ、もうそんな時間?ありがとう!靴下もお願い!」

娘2「はーい!」

娘1「そろそろ髪をくくる時間だな」

妻さん、僕「おー」

苦手なところって

こうしなさいって指摘するより、他の良いところに引っ張られてちょっと良くなるくらいが、楽しくて良いかなぁ。

娘2「おとうさん!そろそろおむかえのじゅんびだよ!」

僕「えーもっとごろごろしてたいー_(:3」∠)_」

なんとなく

娘カテゴリーつくっといた

娘 カテゴリーの記事一覧 - Mitsuyuki.Shiiba

Zaleniumさんに動的にコンテナを立ち上げたり捨てたりしてもらいながらSelenium(というかGebだけど)のテストを実行してその録画を見る

English version of this article is here:

dev.to

Zaleniumってことばを見かけたので触ってみた。

Zalenium?

https://zalando.github.io/zalenium/

ちょこっと触ってみた感じ良さげ

  • 1) ローカルマシンですごく簡単に試すことができる
  • 2) Seleniumのテストを実行するのに合わせて動的にコンテナが起動する
  • 3) テストが録画される

1) ローカルマシンですごく簡単に試すことができる

Zaleinumを起動

# イメージを2つpullしてきて
docker pull elgalu/selenium
docker pull dosel/zalenium

# 実行!
docker run --rm -ti --name zalenium -p 4444:4444 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /tmp/videos:/home/seluser/videos \
  --privileged dosel/zalenium start

(今日の話とは直接関係ないけど、docker.sockのマウントは注意して使いたいね)

で、Live Previewページにアクセスすると http://localhost:4444/grid/admin/live 2つのマシンが起動してることが分かる。

Live Preview

テストを実行する

テストを実行するための環境は立ち上がったから、Seleniumのテストを用意して実行してみよう。

僕は自分の好みでGebで用意したけど、お好きなやつでどうぞ。

http://www.gebish.org/

HelloZelenium.groovy

Browser.drive {
  go "http://gebish.org"

  assert title == "Geb - Very Groovy Browser Automation"

  $("div.menu a.manuals").click()
  waitFor { !$("#manuals-menu").hasClass("animating") }

  $("#manuals-menu a")[0].click()

  assert title.startsWith("The Book Of Geb")
}

Gebのドキュメントからとってきた。読んだら何してるかはだいたい分かるよね。

GebConfig.groovy

driver = {
  def capabilities = new DesiredCapabilities();
  capabilities.setCapability(CapabilityType.BROWSER_NAME, BrowserType.CHROME);
  capabilities.setCapability(CapabilityType.PLATFORM_NAME, Platform.LINUX);

  def remoteWebDriverUrl = new URL("http://localhost:4444/wd/hub")
  new RemoteWebDriver(remoteWebDriverUrl, capabilities)
}

設定はGebConfigに。RemoteWebDriverにZelenium Hub URLを渡してテストを実行する。

import とかを含んだソース全部はここに置いといた: https://gist.github.com/bufferings/a8980ea515a893e21a3a95955ace5dc9

で、実行!

groovy HelloZalenium

したら、Live Previewのページで、テストが実行されてるのが見える。

Live Preview

簡単。

2) Seleniumのテストを実行するのに合わせて動的にコンテナが起動する

複数のテストを同時に実行してみる。

for i in {1..8};do groovy HelloZalenium & done

たら、8つのマシンがコンテナとして立ち上がって、テストが実行されて、シャットダウンするのが分かる。

Live Preview3

3) テストが録画される

デフォルトで全部のテストが録画される。ここで見れる http://localhost:4444/dashboard/#

Recorded Video

設定まわり

こんな感じで設定を渡したりできる:

driver = {
  def capabilities = new DesiredCapabilities();
  capabilities.setCapability(CapabilityType.BROWSER_NAME, BrowserType.FIREFOX);
  capabilities.setCapability(CapabilityType.PLATFORM_NAME, Platform.LINUX);
  capabilities.setCapability("screenResolution", "1280x720");
  capabilities.setCapability("tz", "Asia/Tokyo");

  def remoteWebDriverUrl = new URL("http://localhost:4444/wd/hub")
  new RemoteWebDriver(remoteWebDriverUrl, capabilities)
}

FireFoxで、1280x720で、Asiz/Tokyoで実行されるようになった

Live Preview4

他にも面白そうな機能があるなぁ

  • SauceLabs/BrowserStack/TestingBot連携
  • Kubernetes対応
  • とか

まとめ

Zelenium面白そう。また気が向いたときに触ってみようかな。

数カ月後の自分へ。僕がどういうときにJava10のvarを使いたいと思っているか。

先月リリースされたJava10は、その日に遊んで楽しんだんだけど

bufferings.hatenablog.com

ちょっと時間が経って落ち着いたから、自分の考えを整理しておこうと思った。忘れるので。

この2つを読んだ

どちらもすごく面白いのでおすすめです。

orablogs-jp.blogspot.jp

d.hatena.ne.jp

どちらの記事も言ってるのは「書きやすさよりも読みやすさ」。確かにねー。

僕がどういうときに var を使いたいと思うか

で、僕がどういうときに var を使いたいと思うか。を考えてみたんだけど今のところ、3つかな。

考え方は「読みにくいものが var を使うことで読みやすくなるとき」よね。

1つ目

  • 右辺から型が分かるのに左辺にもそれと同じ型が書いてあるとき

は冗長だから var を使うと読みやすくなりそう。

2つ目は

OpenJDKの方の記事でStuartさんが書いてるG4の

  • チェーンやネストされた式を切って名前付けをしたいとき

は、概念に名前をつけて読みやすくしてるだけだから、ありかな。

このときは、僕は、型を明示することにあまり興味がなさそうだしね。

最後は

きしださんが書いてるみたいに

  • ローカルメソッドの定義

これは面白そうだよね。

数カ月後の自分へ

  • 「右辺から型が分かるのに左辺にもそれと同じ型が書いてあるとき」は冗長だから var を使った方が読みやすそう
  • 「チェーンやネストを切って概念に名前付けをしたいとき」は型を明示的に書くことに興味がないから var を使うと読みやすくなりそう
  • 「ローカルメソッドの定義」は var ならではなので、読みやすくなりそうだったら使おうと思う

もう忘れてると思うけど、今はこんな感じで考えてるよ。

娘たちに部屋のお掃除をやってもらいたいなー

と思って。

とりあえずダメもとで

娘1(9歳)と娘2(5歳)に「寝る前に部屋のお掃除してよ」って言うと

「えー。嫌だ。明日も遊ぶんだからそのままでいいでしょ?」って言うので

「明日、お母さんがお部屋の掃除するときに助かると思うんよ」って言って

娘1,2「はーい」

「じゃ、よろしく!お父さんはお皿洗ってるわ」

(5分後)

ですよね。全く片付いてない。

むしろ新しいおもちゃを出してきて遊んでる。

・・・おまえたち・・・それでこそ我が娘だ。僕も無理だしな。

じゃあ、僕でもできるようにやるか。

ということで、まず部屋1つが相手だとちょい多い。やる気がおきない。遊びたくなる。

それと、30分以内にってなっても、時間が長い。やる気がおきない。遊びたくなる。

そして、終わらない。

僕「じゃ、こうしよう。この畳の上だけをキレイにして?他は全部そのまま。制限時間は3分ね。長い針が8のとこまで。」

娘1「わかった。私がこの畳をやるから、娘2はそっちの畳でどう?」娘2「え?・・・いいけど・・・」

僕「それはダメ。お父さんは二人に協力してやって欲しいんよ。競争してほしいわけじゃない。」

娘1「はーい」娘2「(∩´∀`)∩ワーイおねーちゃんといっしょ!」

僕「よーいスタート!」

勢いよく片付け始めた

ふと気づくと、娘2は別の場所が気になったみたいで、そっちを片付け始めた。

娘1「そこはあとで大丈夫なの。今はこっちよ!」娘2「えっそうなの!?わかった!」

娘1が指示を出して、娘2が走り回る。

3分以内には終わらなかったので、ちょっと延長してあげて。完了。

「うわー!あっという間にめっちゃキレイになったね!(←本当に驚いている」

あとは、その繰り返しで、20分くらいで片付け完了。

最後は

「娘1は全体を見て、娘2には難しい部分をやってあげてて偉かったね」

「娘2はちっちゃい手いっぱいにおもちゃを握って片付けてて偉かったね」

じゃ、お母さんに褒めてもらっておいでー。

みたいな。楽しかった。

選ぶと選ばない

以前は「こういうことができた!」とか「これだけの人の役に立った!」とかそういう、できたことを数えてて、もっとできるようになろう!って思って過ごしてたと思う。

だけど今は、できなかったことの方も考えてしまってる。「何かをすることができた」ってことは「その時間を使ってできたはずの何かをできなかったんだよな」って。

この数年は、自分が関わる範囲がどんどん広がって、しかも会う人会う人みんな好きで、なので、どの人の役にも立ちたい!と思いはするのだけど、僕ができることってせいぜい1つか2つくらいで、なので、例えば30人いて5人のチカラになれたとして、残りの25人のことを僕は選ばなかったんだよなって。

それで別に凹んだり、後悔したりしてるわけでは全然なくて、ただ、そういうことだよなぁって思ってる。

そんなこんなで、今年はできるだけ色んなことをやらないようにしてるんだけど、それはそこに使ってた時間が嫌になったとか飽きたとかそういうのじゃなくて、今も全然好きなんだけどただ単に、その分の時間を家族と一緒に過ごすことを選んでる。というだけかなぁ。

今日は、娘2が楽しみにとっておいたとは全然知らずに冷蔵庫の炭酸水を飲んでしまって、ごめんなさい。

SpringBoot2のBlocking Web vs Reactive WebについてLTしてきた

社内ミートアップでLTの時間をもらったので、ここに書いた内容を3分で喋ろうとしたんだけど、どうしても3分をちょっと超えてしまうので無理を言って4分もらって喋ってきた(運営のみなさんありがとうございます)。ぐったり。明日から普通のエンジニアに戻ります。

dev.to

実感を大切にしてみた

こういうことに気をつけてLTしてみた:

  • ブログの記事に書いてるコードを見せるんじゃなくて、実際のIDE内のソースコードを見せること
  • そのときにIDEAのプレゼンテーションモードで見せること
  • 実際にアプリを動かした状態でcurlで叩いて動いてるのを見せること
  • Gatlingを実際にgradleで実行すること
  • そこでBlockingAppのスレッドが増えるところをVisualVMで実際に見せること

その方が聞いてて「へー。本当に動くんだ」とか「さわってみようかな」とか思ってもらえるかなーと思って。ってことで以下は内容の日本語訳。全部喋ると全然時間が足りないので、実際はこの中の要点だけをpick upして喋った。

バズワードをポッケに

リアクティブなウェブアプリケーションで嬉しいことのひとつは、たくさんのリクエストを少ないスレッドで効率良くさばくことができるってこと。なので、それを実際に自分の目で確認してみようと思う。

f:id:bufferings:20180327215354p:plain

SpringBoot2 Reactive Web

SpringBoot2が今月頭についにリリースされた。その中の大きな新機能がReactive Web対応(Spring5が対応して、それをSpringBoot2でもサポートしたという感じかな)。これまでの、サーブレットAPIベースでブロッキング処理のServlet Stack(下図の右半分)はもちろんそのまま使えるんだけど、それとは別に、リアクティブストリームベースのReactive Stack(図の左半分)というものが追加された。

ので、従来のSpring MVCを使ったアプリと、新しいWebFluxを使ったアプリのパフォーマンスを比べてみる。

f:id:bufferings:20180327220211p:plain (Image from https://spring.io/ )

デモアプリの構成

SpringBoot1とSpringBoot2の比較をしためっちゃ良い記事があったので、これをほぼそのまま参考にしてSpring MVCとSpring WebFluxの比較をすることにした。

dzone.com

こんな感じの構成:

f:id:bufferings:20180327220957p:plain

3つのアプリがある:

  • delay-service
  • blocking-app
  • reactive-app

delay-serviceは外部APIみたいな役割をしてて、300ms待ってからレスポンスを返す。それをblocking-appとreactive-appがそれぞれ呼び出してて、blocking-appはブロッキングなやり方で、reactive-appはリアクティブなやり方で処理してそれぞれレスポンスを返す。このblocking-appとreactive-appのパフォーマンスを比較する。

ソースコードはここに置いといた:

github.com

delay-service

さっきは「delay-serviceは300ms待ってからレスポンスを返す」って書いたけど、実際はパスパラメータで指定した時間だけ待ってからレスポンスを返すようにしてる:

  @GetMapping("/{delayMillis}")
  public Mono<String> get(@PathVariable int delayMillis) {
    return Mono.just("OK")
        .delayElement(Duration.ofMillis(delayMillis));
  }

(最初はブロッキングなやり方で書いてたんだけど、そうするとこいつがパフォーマンスのボトルネックになってしまったので、リアクティブなやり方に変えた)

blocking-app

blocking-appは普通のSpring MVCアプリ。delay-serviceをRestTemplateで呼び出して文字列を返してるだけ:

  private static final String DELAY_SERVICE_URL = "http://localhost:8080";

  private final RestTemplate client;

  public BlockingApp(RestTemplateBuilder builder) {
    client = builder.rootUri(DELAY_SERVICE_URL).build();
  }

  @GetMapping("/{delayMillis}")
  public String get(@PathVariable String delayMillis) {
    String result = client.getForObject("/" + delayMillis, String.class);
    return "Blocking:" + result;
  }

reactive-app

reactive-appはリアクティブになってるんだけど、ほんとにこれまでのアプリを書くのと同じような感じで書ける。delay-serviceをWebClientを使って呼び出して Mono でラッピングした文字列を返すだけ:

  private static final String DELAY_SERVICE_URL = "http://localhost:8080";

  private final WebClient client = WebClient.create(DELAY_SERVICE_URL);

  @GetMapping("/{delayMillis}")
  public Mono<String> get(@PathVariable String delayMillis) {
    return client.get()
        .uri("/" + delayMillis)
        .retrieve()
        .bodyToMono(String.class)
        .map(s -> "Reactive:" + s);
  }

てことで、パフォーマンスをチェックしよう

delay-serviceを起動:

./gradlew -p apps/delay-service clean bootRun

curl -w "\n%{time_total}s\n" localhost:8080/1000
# returns "OK" after 1000ms

curl -w "\n%{time_total}s\n" localhost:8080/2000
# returns "OK" after 2000ms

blocking-appを起動:

./gradlew -p apps/blocking-app clean bootRun

curl -w "\n%{time_total}s\n" localhost:8081/2000
# returns "Blocking:OK" after 2000ms

reactive-appを起動:

./gradlew -p apps/reactive-app clean bootRun

curl -w "\n%{time_total}s\n" localhost:8082/2000
# returns "Reactive:OK" after 2000ms

これで3つとも起動したぞー。

負荷テストのシナリオ

Gatling(https://gatling.io/)を使う。シナリオは「1,2秒の間隔をあけてAPIを30回呼び出すのを1000人のユーザーが実施する」という感じ。初Scala

  val myScenario = scenario("Webflux Demo").exec(
    repeat(30) {
      exec(
        http("request_1").get(targetUrl)
      ).pause(1 second, 2 seconds)
    }
  )
  setUp(myScenario.inject(rampUsers(simUsers).over(30 seconds)))

blocking-appに対してGatlingを実行

./gradlew -p apps/load-test -DTARGET_URL=http://localhost:8081/300 \
    -DSIM_USERS=1000 gatlingRun

VisualVMで見てみると、スレッド数が200まで増えてることが分かる。この200はTomcatのmaxThreadのデフォルト値。

f:id:bufferings:20180327225950p:plain

reactive-appに対してGatlingを実行

./gradlew -p apps/load-test -DTARGET_URL=http://localhost:8082/300 \
    -DSIM_USERS=1000 gatlingRun

こっちはリクエストをさばくのに4スレッドしか使ってないからずっと一定:

f:id:bufferings:20180327230100p:plain

負荷テストの結果

下に結果を貼った。1000ユーザーのときはどちらのアプリも想定通り300msでレスポンスを返してる。けど、blocking-appのパフォーマンスは3000ユーザー、6000ユーザーに対してだんだん悪くなってる。

一方で、reactive-appはずっとグリーンのまま。最終的には6000ユーザーに対して95パーセンタイルが427msで、2000rpsくらい処理してる。(Core i7-7500U 2.7GHz/16GB RAMで確認)

へー。実際に書いて動かしてみると面白いね。

blocking-app

with 1000 users: f:id:bufferings:20180327230708p:plain

with 3000 users: f:id:bufferings:20180327230721p:plain

with 6000 users: f:id:bufferings:20180327230736p:plain

reactive-app

with 1000 users: f:id:bufferings:20180327230750p:plain

with 3000 users: f:id:bufferings:20180327230808p:plain

with 6000 users: f:id:bufferings:20180327230835p:plain

やり残し

TomcatのmaxThreadsのチューニング

今回はデフォルト設定のままで比較してみたんだけど、TomcatのmaxThreadsをチューニングしたら良いパフォーマンスが出そうではある。600rpsという数字も300msかかる処理を200スレッドで処理してるんだったらそうだろうという感じよね。

環境の分離

自分のノートPCで全部動かして確認したから、アプリとdelay-serviceとGatlingがそれぞれ作用しあってたよなーって思う。特にCPU。なので、環境をキレイにわけて別のマシンで動かしてるやつでパフォーマンスをちゃんと見たらまたちょっと違うのかなーと。

まとめ

面白かった。マイクロサービスアーキテクチャみたいにいっぱいAPIを呼び出すような場合は、リアクティブなやり方だと待ち時間が有効に使えるから良さそう。ただ、リアクティブプログラミングは、これまでサーブレットブロッキングな処理を書いてきたエンジニアにとっては頭の切り替えが必要だろうから(僕もそう)、そういう人はちょくちょく触って遊んでおくといいんじゃないかなー。

ということでWebFluxをポッケに入れといた。よー。今回はMonoだけを使ったけど、Fluxでごにょごにょしてみるのも面白そうだなー。