hitomedia Tech Blog

株式会社ヒトメディアのテクノロジーに関するブログです

非エンジニアにプログラミングを教えた話

ヒトメディアでサーバサイドエンジニアしております、@nakaearth です。

今回は少し前の話になりますが、出向先で非エンジニアにプログラミング講習をした話です。

どんな講習をしたのか

そもそもどうして非エンジニアに対しプログラミング勉強会をすることになったのか。きっかけは企画の方との会話からです。

f:id:nakaearth:20180501111117p:plain

そして開催することに

f:id:nakaearth:20180501111246p:plain

参加者はそれほど多くないと思っていたのですが、結構多かったです。

f:id:nakaearth:20180501111338p:plain

予想以上の参加人数だったので、マシンの都合もあり二人一組でやっていただくことにしました。講師側は私ともう一人の二人体制にしました。 講習内容ですが、rubyを使った文字列操作やループ処理などの簡単なプログラミングを体験するものにしました。

f:id:nakaearth:20180501113318p:plain

所感

環境設定でつまずく

まず最初に躓いたのでは環境設定のところでした。あらかじめ「このマシン使ってやってください」と用意すればよかったかもしれませんが、準備ができず当日参加された方々のマシンにRuby環境やエディタをそれぞれ作るのに時間がかかってしまいました。そこの手順も明確にしておくか、可能なら事前に済ませておけば良かったと思いました。

説明は細部まで丁寧に

ruby -vをしてくださいと言った時に受け取り方が様々でした。ruby-vだったりruby - vだったり。普段自分が何気なくやって当たり前と思うことでも注意して話をしないと伝わらないと改めて思いました。

動いたものを見るとテンションが上がる

自分たちで書いたプログラミングが動くのを見ると盛り上がります。動いたら自分たちで少しずつ変えて実行結果がどう変わっていくのか見てもらいました。

後日

後日アンケートをしたら前向きな意見が結構多かったのでやってよかったと思います。非エンジニアの方も結構プログラミングに興味あるようで、第2回目があれば参加したいいう声が結構ありました。 そこで・・・・近日中に第2回目をやるにしました。その様子もまたブログに書こうと思います。

ノンデザイナー向けに「デザインとはなんぞや勉強会」をした話

デザイナーのばっこ(@is178)です。

ヒトメディアでは、毎月有志が集まって勉強会を開いているのですが、先月、ノンデザイナー向けに「デザインとはなんぞや」という発表をしまして、その時の資料を公開したいと思います。

デザインとはなんぞや

f:id:is178:20180410164813p:plain 「デザイン」と聞くと、最初に思い浮かぶのはきっと、華やかな感じの、センスがどうとかクリエイティブがどうとか、何か見た目が良いものを作るようなイメージが強いと思います。

しかし、それはあくまでデザインの一面であり、僕の場合は、UXデザインとか、サービスデザインとか、もう少し広い意味の、地味な方のデザインに興味があります。

今回は、その辺りの関係性とか、それぞれどういうことをするものなのかとか、僕の認識をまとめました。まずは概念のお話をして、土台となる共通認識を作れればと思います。

デザインはめっちゃ範囲が広い

f:id:is178:20180410164817p:plain デザインと一言に言っても、対象範囲がめっちゃ広いです。

パッと思いつくだけでも、都市デザイン、建築、インテリアデザイン、ファッションデザイン、プロダクトデザイン、コミュニティデザイン、サービスデザイン、Webデザイン、グラフィックデザイン、UIデザイン...

同じデザインと名のつくものでも、別の分野になれば、素材も加工方法もまるで違う未知の世界です。 今回は僕がわかる範囲のデザインについてお話ししますが、それ以外にもいろいろな「デザイン」があることは頭においておいてもらえると助かります。

グラフィックデザイン、UIデザイン、UXデザイン

f:id:is178:20180410164830p:plain 僕がわかる範囲のデザインは、僕が今まで経験してきたデザインで、この3つになります。

それぞれ定義があってないようなものなのですが、僕の解釈ではこの図のような関係性で、 グラフィックデザインとUIデザインはかぶる領域がありつつ、それらは全てUXデザインの中の要素、というイメージです。



ひとつ断わっておきたいのが、ここでは純粋に「○○デザイン」のお話をするのであって、「○○デザイナー」のお話をするわけではありません。*1

それぞれの特徴

f:id:is178:20180410180519p:plain グラフィックデザインは、商品を売るための手段です。いわゆる広告です。 これ単体で考えると、商品が売れさえすれば良いという、商業に魂を売りがちなデザインでもあります。

UIデザインは、使い勝手を高めるための手段です。 対象をインターフェイスに限定して注力するので、自然と細部まで意識することになり、せっかくのこだわりが自己満足になりがちなデザインでもあります。*2

UXデザインは、他二つのように「売ったり、使いやすくしたり」することをゴールにするのではなく、その先で良い体験を生むための手段です。 ただ、それを実現するためには、前述の2つのデザインや他の要素も必要になるので、これ単体ではただ理想論を振りかざすだけになりがちなデザインです。

では、一つずつ詳しく見ていきます。

グラフィックデザインは「視覚(ビジュアル)のロジック」を考える

f:id:is178:20180410164837p:plain グラフィックデザインの目的は、広告・販売促進のためのスタイリング(雰囲気、美しさ、心地よさを演出)。スタイリングによって情報整理、価値の付与をします。

芸術色が強く、斬新なものが好まれがちです。 また、分業によって専門性が高められた結果、スタイリングによって成果を出すという本来の目的から外れ、正確な効果検証などがされず、単に見た目の美しさを評価するアートのような扱いを受けている面もあります。

よく「デザインってセンスだよね」と言われるのがこの分野だと思うのですが、ほとんどの場合、天性の才能だとか、神の啓示によってデザインしているわけではなくて、作る時間と同じくらいかそれ以上にリサーチをした上で制作するのが一般的です。

また、「こういう時はこうしましょう」というお作法もたくさんあるので、そういったことを元に「視覚(ビジュアル)のロジック」を考えるデザインです。

デザイン対象:紙、Webサイト(PC)、商品パッケージ、デジタルサイネージ、etc…
デザインスキル:情報設計、レイアウト、配色、タイポグラフィ、コピーライティング、ロゴデザイン、アイコンデザイン、写真加工、イラスト、etc…


UIデザインは「対話(インタラクティブ)のロジック」を考える

f:id:is178:20180410164842p:plain UIデザインの目的は、使いやすさ・分かりやすさを高めることです。

「複雑な機能を持つプロダクトが増えた」「機能や見栄えだけでは売れなくなってきた」という流れから、 使い勝手が注目され始めて、人間工学や認知心理学の考え方がデザインに持ち込まれるようになったという経緯があります。

よくグラフィックデザインの一部だと済ませられがちですが、単にそれっぽいものを作って終わりではなく、「作ったものが実際使われたらどうなるか、そのあとの改修はどうするか」といったところまで踏み込めてこその「UIデザイン」だと僕は考えています。

斬新なものが好まれるグラフィックデザインとは逆で、とにかくガイドライン準拠、「標準」から逸脱しないことが好まれがちです。 余計なことをせずに、変に記憶に残らない、ユーザーに意識されないUIが良いUIなので、地味な仕事ではあります。

モノだけではなく利用者にも目を向けて、使い勝手を高めるために「対話(インタラクティブ)のロジック」を考えるデザインです。

デザイン対象:Webサイト(モバイル)、アプリ、(デジタル)プロダクト、etc…
デザインスキル:利用文脈の理解、対象媒体のデザインガイドラインの理解、人間工学、認知心理学、ユーザーテスト、etc

UXデザインは「工程(プロセス)のロジック」を考える

f:id:is178:20180410164846p:plain UXデザインは、単なる見た目の良さや使いやすさを超えて、それらが良い体験を生み出すことを目指します。 
プロダクト起点ではなくユーザー起点で、最終的に提供したい体験から作るものを逆算するため、プロダクトである必要もなくなる場合もあります。

アウトプットとしては、ユーザー調査の結果や学びを共有するための資料、仮説検証のためのプロトタイプ、課題や解決策などの認識合わせをするための資料など、それ自体がユーザーに直接影響を与えることのない、中間制作物が多くなります。


プロダクトが良い体験を生むために、チームが正しいものを正しく作る「工程(プロセス)のロジック」を考えます。

デザイン対象:ユーザー、チーム、ワークフロー、etc...
デザインスキル:ユーザーインタビュー、ジャーニーマップ 、プロトタイピング、etc…

デザインがデザイナー以外にも解放された

f:id:is178:20180410164851p:plain UXデザインの大きな特徴として、「デザインがデザイナー以外にも解放された」というところがあるように思います。

というのも「グラフィックデザイン」や「UIデザイン」は、基本的には前提となるプロダクトを疑わずに「どう見せるか」を考える部分であり、デザイナーは製作フローに途中参加する形でした。

ところがUXデザインにおいては、制作フェーズより前の段階や後の段階にも関わることになるので、デザインの範疇が一気に広がりました。 それと同時に、デザインがデザイナーだけの手に負えるものではなくなってしまったので、全てのフェーズでチームの協力が必要になります。

UXデザインは、単なるバズワードではなく、デザインの在り方を大きく変える考え方を持ち込みました。

デザイン≠センス、デザイン≠ロジック

f:id:is178:20180410164900p:plain 最後に、これだけ覚えておいてもらいたいのが、 紹介したこれらのデザインはすべて、センスではなくロジックだということです。

もしかしたら、世界トップ数%のクリエイターは天性の「センス」で仕事をしているかもしれないのですが、 基本的には、グラフィックもUIもUXも、なぜそうデザインするのかに理由があり、ひどいデザインには大抵ロジックがないです。

この主張をする理由は2つあって、「デザインってセンスだよね〜」で済まされてしまうと、

  • アウトプットに至る過程の努力(日頃の勉強、製作時の調査やラフ制作など)がまるで無かったことになってしまう
  • デザインの範囲が広がり、チームでデザインする必要が出てきた今、「デザインはセンス」という考え方がハードルになってしまう

という二点から、「デザイン=センス」という意見は、積極的に否定していきたいと考えています。

終わりに

ヒトメディアでは現在デザイナーもエンジニアも募集中です! よろしくお願いします!

Twitterもやってます!良かったらフォローしてください!(@is178

www.wantedly.com

www.wantedly.com

*1:何が言いたいのかと言うと、グラフィックデザイナーはUIデザインもUXデザインもすることがあるので、「グラフィックデザインの特徴=グラフィックデザイナーの特徴」とはなりません。

*2:というのも、ほとんどの場合、どう作るかより何を作るかの時点で勝負が決まっていたりするので...

RSpecで悲観的ロックのテストを書く

こんにちは。花粉症で鼻水が止まらない日々が続いている hilotter です。

同一レコードに対し複数ユーザ(もしくはバッチ処理等)から同時に更新される可能性がある場合、排他制御を行う必要があります。

今回はシンプルなポイント付与機能を例に、悲観的ロックを用いた排他制御のテストを書いてみたいと思います。

シンプルなポイント付与機能仕様

  • ユーザは他のユーザにポイントを送ることができる

今回のサンプルは以下の環境で確認しました。

  • Rails 5.1.4
  • MySQL 5.7.20
  • MySQLのトランザクション分離レベル REPEATABLE-READ(デフォルト設定)

add_pointメソッドの実装

  • Userモデルにポイントを付与できるadd_pointメソッドを追加します

transaction内でlock!を用いて悲観的ロックをかけています。

# app/models/user.rb

class User < ApplicationRecord
  def add_point(point)
    ActiveRecord::Base.transaction do
      lock!
      self.point += point
      save!
    end
  end
end

RSpec

続いてテストを書いていきます。

RSpecのデフォルト設定では、テスト用のデータ登録を行った際に素早くデータのクリーンアップができるようにトランザクション内でテストが実行され、テストが終わった際にトランザクションがロールバックされるようになっています。

今回はトランザクションのBEGIN ~ COMMITが正しく行われることを確認したいため、この設定を無効化します。 1

# spec/rails_helper.rb

config.use_transactional_fixtures = false

続いて本題のUserのspecを書きます。

Threadを用いてポイント付与のメソッド(add_point)を同時に呼び出すようにします。

# spec/models/user_spec.rb

require 'rails_helper'

RSpec.describe User, type: :model do
  describe "#add_point" do
    # 100ポイントを持っているAさん
    let!(:user) { create(:user, point: 100) }

    context "2人のユーザから同時更新された場合" do
      before do
        threads = []
        threads << Thread.new do
          ActiveRecord::Base.connection_pool.with_connection do
            # Bさんから10ポイントを付与
            u = User.find(user.id)
            u.add_point(10)
          end
        end
        threads << Thread.new do
          ActiveRecord::Base.connection_pool.with_connection do
            # 同じタイミングでCさんから50ポイントを付与
            u = User.find(user.id)
            u.add_point(50)
          end
        end
        threads.each(&:join)
      end

      it { expect(user.reload.point).to eq(100 + 10 + 50) }
    end
  end

specの実行とtest logの確認

bundle exec rspec を実行するとテストが通ります 🎉

test実行時のクエリログも確認してみましょう。

# log/test.log

(0.6ms)  BEGIN
(1.6ms)  BEGIN
User Load (2.0ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 178 LIMIT 1 FOR UPDATE
User Exists (0.9ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = 'user1@example.com' AND (`users`.`id` != 178) LIMIT 1
SQL (0.9ms)  UPDATE `users` SET `point` = 110 WHERE `users`.`id` = 178
User Load (13.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 178 LIMIT 1 FOR UPDATE
(4.5ms)  COMMIT
User Exists (4.1ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = 'user1@example.com' AND (`users`.`id` != 178) LIMIT 1
SQL (0.9ms)  UPDATE `users` SET `point` = 160 WHERE `users`.`id` = 178
(6.2ms)  COMMIT

悲観的ロックにより、1つ目のupdateの完了を待ってから、2つ目のupdate文が実行されています。

悲観的ロックをかけなかった場合

悲観的ロックをかけなかった場合の実行結果も確認しておきましょう。

# app/models/user.rb

class User < ApplicationRecord

  def add_point(point)
    ActiveRecord::Base.transaction do
      # lock!
      self.point += point
      save!
    end
  end
end

この状態でrspecを実行すると、150が結果として返ってきてしまいました。

(実行の度に結果が変わるため150もしくは110が返ってきます)

F

Failures:

  1) User#add_point 2人のユーザから同時更新された場合 should eq 160
     Failure/Error: it { expect(user.reload.point).to eq(100 + 10 + 50) }

       expected: 160
            got: 150

クエリログを確認してみると、ロックをかけていないため(100 + 10)のupdate文と(100 + 50)のupdate文が実行されてしまい、2つ目のupdate文によって1つ目のupdate文の結果が失われてしまっています。(ロストアップデート)

# log/test.log

(0.5ms)  BEGIN
User Load (0.8ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 179 LIMIT 1
(0.8ms)  BEGIN
User Exists (1.1ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = 'user1@example.com' AND (`users`.`id` != 179) LIMIT 1
User Exists (1.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = 'user1@example.com' AND (`users`.`id` != 179) LIMIT 1
SQL (4.9ms)  UPDATE `users` SET `point` = 150 WHERE `users`.`id` = 179
SQL (9.5ms)  UPDATE `users` SET `point` = 110 WHERE `users`.`id` = 179
(5.7ms)  COMMIT
(2.0ms)  COMMIT

まとめ

同時実行処理の手動確認は難しいですが、Threadを用いることで同時実行処理をテストできるようになりました。

もっとシンプルに書く方法や、こうするとより良い等ありましたらアドバイスいただけますと嬉しいです。

参考


  1. データのクリーンアップに関してはdatabase_rewinderを利用しています。

prprでGithubのPullRequestレビュー依頼をSlack通知する

最近サーバサイドをやりつつiOSアプリ開発をやったり何でも屋になっている hilotter です。

GithubのPullRequestレビュー機能、便利ですね。

チーム開発においては相互レビューが非常に大事です。

今回は、レビュー依頼を行った際にSlackに自動通知するようにしたらより便利になったというお話を共有させていただきます。

SlackのGitHub連携の課題

Slack公式のGithub連携がありますが、こちらは以下の2点が課題となっていました。

1. メンション付きのコメントをしても、message-attachmentsの記法になっているため、うまく通知されずコメントを見落としてしまう

f:id:hilotter:20170824122029p:plain

このため、コメント後にSlackでも「コメントしました!」と2重で連絡をする必要がありました。

2. PullRequestのレビュー依頼を行ってもレビュアーへの通知が飛ばないため、レビューすべきPullRequestに気づけない

f:id:hilotter:20170824122242p:plain

こちらも同様にレビュー依頼の後、Slackでも「レビューお願いします!」と2重で連絡をする必要がありました。

prpr

これらの課題を解決するために、 githubのプルリクエストに反応するbotフレームワークであるprprを使わせていただくことにしました。

ぺろぺろ - Github pull request bot framework - - みずぴー日記

prpr及び、prpr-mention_commentプラグインを用いることで、課題1に挙げた「メンション付きのコメントをSlackに通知できない」を解決することができました。

また、よくある問題として「Githubのユーザ名とSlackのユーザ名が異なる」というのがありますが、この場合もMEMBERS.md というユーザ名の対応表を作って該当リポジトリにコミットすればユーザ名を変換してくれるので安心です。

MEMBERS.mdの記述方法

記述がない場合は、そのままのユーザ名で通知されるので、MEMBERS.mdには変換が必要なユーザのみを書いておけばOKです。

 * @Githubのアカウント名1: @Slackのアカウント名1
 * @Githubのアカウント名2: @Slackのアカウント名2

prpr-mention_reviewers

課題2の「PullRequestのレビュー依頼を行ってもレビュアーへの通知が飛ばない」に関しては、既存プラグインが見つからなかったのでプラグインを作ってみました。

prpr-mention_reviewers

できることとしては以下になっています。

  • PullRequestのレビュー依頼を行った際に、指定したchannelに通知
  • レビュー依頼時のテンプレート文言を設定
  • オプションで指定channelの代わりにDMで通知

DM通知オプションは一応作ってみたものの、PullRequestは可能な限り多くの人の目を通した方がいいと思うので社内では使っていません。

また、prpr-mention_reviewersはprpr-mention_commentと同時に利用することを想定しているため、通知先チャンネルを指定する環境変数(MENTION_COMMENT_ROOM)とユーザ名の対応表ファイルを指定する環境変数(MENTION_COMMENT_MEMEBRS)はprpr-mention_commentと同じ環境変数名を利用することにしました。

プラグイン開発Tips

Configuring your server | GitHub Developer Guide にあるようにngrokを用いて、ローカル環境にWebHookを通知するようにして開発を進めると捗りました。

使い方

prpr-templateにならってHerokuにデプロイするのが一番手軽です。

ということで、prpr-mention_reviewers版 prpr-template を作ってみました。

とりあえず試してみる場合

  • SlackのIncoming WebHooksを作成

  • GithubのAccessTokenを作成

    • ユーザ名変換の際に該当リポジトリのファイルを読み込む必要があるためrepoのフル権限が必要になります
  • prpr-mention_reviewers版 prpr-template にアクセスし、「Deploy to Heroku」ボタンをクリック

  • 環境変数入力画面が表示されるのでSLACK_WEBHOOK_URLとGITHUB_ACCESS_TOKENを入力しデプロイを実行

  • 通知を行いたいGithubリポジトリのWebhook設定画面を開き、HerokuアプリのURLを設定 f:id:hilotter:20170824123949p:plain

これで導入完了です!

Slackの通知先channelを変更したい場合は別途、環境変数MENTION_COMMENT_ROOMを設定してください。

また、MENTION_REVIEWERS_BODYにレビュー依頼時のテンプレート文言を設定できます。

社内で設定している環境変数は以下のようになっています。

MENTION_COMMENT_ROOM - #github-mention
MENTION_REVIEWERS_BODY - %{title} のレビューをお願いします :pray:

この状態で、PullRequestのレビュー依頼を行うと、以下のようにSlackに通知されます!

f:id:hilotter:20170824124457p:plain

運用Tips

slackのユーザ名をGithubのユーザ名と同じにしたけど通知が飛ばない場合

slackアプリ上のプロフィール編集でユーザ名を変更するとdisplay_nameという項目が変更されますが、name自体は以前のままになっています。

この場合、Webサイト上からusernameの編集を行う必要があります。

↓のURLにアクセスし、usernameを変更すると通知が飛ぶようになります。(team名は各自変えて下さい)

https://{your_team}.slack.com/account/settings?updated_username=1#username

f:id:hilotter:20180507161026p:plain

まとめ

prprを使うことで、SlackのGithub連携機能の課題を解決することができました。

また、prprはプラグインが作りやすい設計になっているので素早くプラグイン開発ができて助かりました。

今後、Githubに新機能が増えた場合も手軽にプラグインを作っていけそうです!

「GithubのPullRequestレビュー依頼をSlack通知したい」とお考えの場合はぜひ試してみてください。

ruby-jmeterで負荷テストをした話とTips

こんにちは。id:Tetsujinです。

ヒトメディアでは、いろいろとWebアプリケーションの開発や運用をしていますが、自社のものなのか、お客様向けに納品するのものなのか、などで作るものに求める・求められるレベル感も変わることが多く、アプリケーションの性能要件の決め方や、計る手法が確立していません。

いままでも、シンプルに測定するのはSiegeを使ったり、シナリオを組む場合はJMeterを使うこともあれば、Load Impactを契約して利用したこともありました。

また、テスト結果のレポート提出が必要な場合は、自分たちで実施せずにテスト会社様にお願いをしたりと、都度都度、状況にあわせてやる、やらない、やり方を決めていました。

最近、改めてJMeter(お客様の要望もあり)で負荷テストをすることがあり、これを機にもう少しノウハウを蓄積していこうと取り組んだので、Tipsを共有します。

ruby-jmeterについて

ruby-jmeterを使うと、RubyDSLでテストシナリオを書いてjmx(JMeterの設定ファイル)を生成することができます。

https://github.com/flood-io/ruby-jmeter

  • JMeterGUIでポチポチ操作しなくてよくなる。
  • テストシナリオがコードでバージョン管理できる。
  • いつでもテストシナリオを再生性可能であるという安心感。

ただ、結局JMeter自体の知識は必要となるので、JMeterのドキュメントは読む必要がありますし、それに対応するruby-jmeterのコードってどうなるんだっけ?とDSLの中身を追いかける必要もでてくるので、 敷居が低いのかというと、そうでは無いと感じています。

インストール方法や使い方などはインターネット上に、非常にわかりやすい記事が沢山あります。

Tips

今後も他のアプリケーションに対して、ruby-jmeterを使う時にも流用しようかなと思っているTipsです。

環境変数で環境毎の設定を変更する

direnvdotenvなどを使って環境変数で、テスト対象の環境毎の細かな設定変更をするようにしました。

JMeter的には、 user_defined_variables で変更すべき項目なのかもしれませんが、都度、設定変更するのも面倒なので環境変数で定義しておいて差し替えられるようにしています。

ローカル環境ではBASIC認証をかけていませんが、ステージング環境ではかけていたのでその切り替えや

if ENV["JMETER_AUTH_USER"]
  http_authorization_manager url: ENV["JMETER_BASE_URL"],
                             username: ENV["JMETER_AUTH_USER"],
                             password: ENV["JMETER_AUTH_PASSWORD"]
end

ステージング環境ではJMeterのクライアント側マシンのファイルパスが異なったためその切り替えや

csv_data_set_config filename: "#{ENV["JMETER_DATA_DIR"]}/data1.csv"

direnvを使って、負荷テストを実施する環境に応じてjmxを生成できるようにしています。

.envrc

export JMETER_BASE_URL="https://example.com"
export JMETER_DATA_DIR="$PWD/data"

.envrc.d/staging/.envrc:sh

export JMETER_BASE_URL="https://staging.example.com"
export JMETER_AUTH_USER="user"
export JMETER_AUTH_PASSWORD="password"
export JMETER_DATA_DIR="C:\\jmeter\\data"

Gemfile

source 'https://rubygems.org'
gem 'ruby-jmeter'

コマンドラインから生成します。

# ローカル向け
$ bundle exec ruby generate_jmx.rb

# ステージング向け
$ direnv exec .envrc.d/staging bundle exec ruby generate_jmx.rb

ロジックの共通化

今回のプロジェクトでは、シナリオ毎の共通点が多かったのでログイン処理などは一部、モジュールに切り出して共通化しました。

module/auth.rb

module Auth
  def login
    -> {
      visit name: "ログイン - 表示", url: "#{ENV["JMETER_BASE_URL"]}/login" do
        extract name: "csrf-token", xpath: '//*[@id="_token"]/@value', tolerant: true
      end

      submit name: "ログイン - 実行", url: "#{ENV["JMETER_BASE_URL"]}/login", always_encode: true,
             fill_in: {
               "LoginForm[_token]"   => "${csrf-token}",
               "LoginForm[login_id]" => "${login_id}",
               "LoginForm[password]" => "${password}",
             } do
      end
    }
  end
end

generate_jmx.rb

require 'ruby-jmeter'

require_relative 'module/Auth'
include Auth

test name: 'example' do
  threads name: "シナリオ1", count: 10, loop: 1 do
    csv_data_set_config filename: "#{ENV["JMETER_DATA_DIR"]}/data1.csv",
                        shareMode: "shareMode.group",
                        quotedData: true,
                        recycle: false,
                        stopThread: true,
                        fileEncoding: "Shift-JIS"
    cookies
    login.call
    # 以降、シナリオのコード
    # ...
  end
end.jmx(file: 'example.jmx')

あまりやり過ぎると、シナリオの見通しが悪くなるため、適度にやるのがよさそうです

テストデータの定義

負荷テストのシナリオで利用するテストデータは csv_data_set_configCSVを読み込んでいます。

csv_data_set_config filename: "#{ENV["JMETER_DATA_DIR"]}/data1.csv",
                    shareMode: "shareMode.group",
                    quotedData: true,
                    recycle: false,
                    stopThread: true,
                    fileEncoding: "Shift-JIS"

今回のプロジェクトでテストに必要なデータは、1レコードにつき100列ほど定義が必要だったため、CSVを直接管理するのは無理だ。と感じて結果的にExcel管理にしました。

もう少し良い管理方法はありそうなのですが、お客様に「このデータでテストします〜」という提示、ファイルの受け渡しも必要だったので容易さも考えてExcelで。

こんな感じでシナリオ毎のデータをシートを分けて定義しておき、CSVに変換します。 f:id:Tetsujin:20170722155227p:plainf:id:Tetsujin:20170722155235p:plain

1列目のヘッダが変数名となり、参照できるようになります。

submit name: "ログイン - 実行", url: "#{ENV['JMETER_BASE_URL']}/login", always_encode: true,
       fill_in: {
         'LoginForm[_token]'   => '${csrf-token}',
         'LoginForm[login_id]' => '${login_id}',
         'LoginForm[password]' => '${password}',
       } do
end

さいごに

というわけで、今回プロジェクトでruby-jmeterを使ってみましたが、なんでもかんでもruby-jmeterでシナリオ書いて負荷テストをするか?と言うと、そうは考えてません。

以下のような場合は、ruby-jmeterが有用だと思っています。

  • テスト対象のアプリケーションの仕様をコードレベルで把握している。
  • 使い捨てじゃなくて、継続的にテストを管理・実行していくつもりがある。

ですが、テスト対象のアプリケーションの仕様をあまり把握はしてないけどテストをすると言う場合は、無理にruby-jmeterは使わず、JMeterのHTTP Proxyをブラウザに通して、ブラウジングを記録させてシナリオを作っていた方が、効率的なんじゃないかなと思っています。

参考: http://inokara.hateblo.jp/entry/2015/08/25/060119

オフィスの空気をモニタリングして改善する話

今年、35歳エンジニア定年説の年齢になり
体調に不調をきたし、もっぱら瞑想と体調管理の本ばかり読んでいるid:kenjiskywalkerです。

最近のおすすめは

この辺です。

オフィスの改善

今回の話はオフィスの空気(物理)を改善するための施策を行ったお話です。

前提

オフィスで働いているメンバーから、オフィスの空気(物理)が
悪い印象があるという声が多くありました。

技術勉強会でこの話をした時に参加者に「空気(物理)が悪いと感じたことがありますか」
とインタビューしたところ、8割以上のメンバーが感じたことがある。と回答していました😅

もし、執務室の二酸化炭素濃度が高く、メンバーのクリエイティビティが
下がっている可能性があるのなら、そこは改善しようという運びとなりました。

参考

チームラボオフィスの空気環境(CO2)を測定して改善している話:tks(高須 正和)のブロマガ - ブロマガ

課題選択

まずは本当に空気が悪いのかモニタリングをすることにしました🌡

解決方法

MH-Z19BME280を利用し
Raspberry Piにて計測しようと思ってチャレンジしてみましたが
MH-Z19がうまく二酸化炭素濃度を測れずあきらめました😇

Netatmo

https://www.netatmo.com/ja-JP/product/aircare/homecoach

利用したのはこちら

なにができるか

これらを計測できるものです。

いくらするの?

21,795円🙄

会社の環境改善ということで経費で購入させてもらいました🙇

ということで

netatmoを利用して

を計測するようにしました

f:id:kenjiskywalker:20170629164823p:plain

取得したデータをどのようにモニタリングするか

都度Webで確認するのも手間なので
APIからデータを取得してSlackに通知するようにしました⛩

  • APIの参考URL

Oauth

https://dev.netatmo.com/resources/technical/guides/authentication/clientcredentials

データ取得 https://dev.netatmo.com/resources/technical/reference/weatherstation/getstationsdata

参考コード

  • 設定した閾値を超えたら通知するくん🚀

https://gist.github.com/kenjiskywalker/4d5fcb9a9edf6dd754c6594d830351a4

どこで動かしている?

社内においてあるRaspberry Piのcronで動かしています😉

どうやって通知している?

こんな感じで通知されます

f:id:kenjiskywalker:20170629165247p:plain

結果どうだった?

たまに二酸化炭素濃度が1600pmを超えるタイミングもありましたが
その度に主導で窓を開けたりして対応し、二酸化炭素濃度は落ち着きました。

また、加湿器が動いていなく
冬の時期に湿度が30%を切るタイミングに気づけたり、
勉強会でのアンケートで、botが動くようになってから
「会社の空気(物理)が良くなったか?」というアンケートで 9割を超えるメンバーが「良くなったと実感した」という回答をしてくれて

21,795円🙄を無駄金にせずにすみました。
今後はIoTで自動で窓の開閉までできると良いなと考えています☺️