「服従の心理」を読んだ
- 作者: スタンレーミルグラム,山形浩生
- 出版社/メーカー: 河出書房新社
- 発売日: 2012/01/07
- メディア: 文庫
- 購入: 4人 クリック: 16回
- この商品を含むブログ (29件) を見る
先日参加したアジャイルジャパン新横浜サテライトで視聴した基調講演の中で、この本が取り上げられていた。 どういった文脈でこの本に触れていたのかは記憶があやふやだったのだが、フラットな組織についての文脈だったと思う。
この本は、人が権威に服従する仕組みを調査する実験について、その実験方法から被験者の記録、分析について、実験を主導したミルグラム本人によって書かれたもの。ミルグラム実験がどういうものかについては、Wikipediaにも掲載されているのでそちらを読んでください。
この本を読んでいて思うのは、人間が恐ろしくもたやすく権威の支持に服従してしまうということだ。 ミルグラム実験では、被害者(実際には実験する側である役者)に対して、被験者が電撃を加える。電撃の電圧を上げていくなかで、被害者が実験の中止を求めたり、体調不良を訴える。もし被験者が実験者に対して実験の中断を申し出ても、実験者は継続するように促す。 ここで被験者はどう行動するのか?
これを実験に参加していない人にアンケートを取ると、被害者が申し出た時点で被験者は実験を中止するだろう、と回答する。 特に、大学生、特に心理学を専攻している学生であるほど、より早く中止するだろうと回答している。 しかし、実験結果は、最悪のもので、被験者のほぼ全員が加えられる最大の電圧まで電撃を与え続ける。
支持の内容が非人道的だとわかっていても、責任が権威にあるとして続けてしまう。社会の中で生きるように進化してきた人間として、権威からの支持に従うことで社会の構成員として存在意義を示す傾向にあるとも言われている。
実験の種類もいくつも試されており、服従しないようにするためにはどのようにすればいいのか調査されている。 被害者と被験者との物理的な距離や、権威を持つ実験者の支持の一貫性が崩れた時や被験者を複数にするなど様々なことを試している。 それぞれの実験結果については、この本を実際に読んでみてほしい。
感想
- 普段の社会にいたら、権威というものはいたるところに現れる。当然、仕事をしている時なんかは「上司と部下」といったものがそこら辺にある。非人道的な指示ですらあっさり服従してしまうのだから、普段の仕事でも無駄とわかっているようなことをあっさりと何も考えずにこなしてしまうのではないだろうか。
- 上司の指示が必ずしも正しいわけではないし、それは上司が悪いと言って終わりにしてしまうわけにもいかないと個人的には思う。誤りをどこかで訂正するためには、服従に抵抗しなければならない。そのためのヒントがこの実験にあるんじゃないだろうか。
- マネジメントは、人に働きかけて全体としてうまくやろう、というものだと思うので、人について知らないといけないだろうから心理学から学べることが多そう。
なんだかホラー映画を見ているような感覚で読んでいた気がする。
VS Code Recipes でRailsのデバッギング環境を構築してみた
Microsoft がVisual Studio Codeの設定のレシピをGitHub上に公開している。 その中に、Ruby on Railsのデバッグ環境の構築方法があったので、試しにそれに倣って作ってみた。
やってみた中で、自分なりに置き換えた部分がありました。
デバッグで使うgemをGemfileに追加
デバッグで使用するruby-debug-ide
とdebase
をGemfile
に追加する。
理由としては2つある。
- それらのgemがデバッグに必須であるので、Railsアプリケーション開発に必要なものとして必要であることを明示するため。
- あとで作成するデバッグの設定ファイル
launch.json
内で、rdebug-ideコマンドのパスを絶対パスとして指定する必要がある。そのパスを開発環境に依存させないようにしたいため。
2については後に出すlaunch.json
を見てください。
具体的には、以下のようにGemfile
に記述する。
group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' gem 'ruby-debug-ide', require: false # <= Added gem 'debase', require: false # <= Added end
gem
のrequire
オプションにfalse
を指定している。これは、Railsが起動時にBundle.require
で依存しているgemを全てrequire
で読み込むのだが、アプリケーション自体には必要無いので読み込まないようにする。
このオプションを指定しなくてもデバッグはできるのだが、必要ないものはあえて読み込まないでおくほうが健全だと思う。
launch.json
デバッグ時に起動するアプリケーションやスクリプトを記述するためのlaunch.json
ファイルも、vscode-recipesにサンプルが記載されている。
サンプル中に出てくる、rdebug-ide
やbundler
コマンドのパスを指定するオプションpathToRDebugIDE
とpathToBundler
は、絶対パスで指定する必要がある。
まず、上でGemfileに依存を記述したので、bundle binstubs
コマンドを使って、bin
ディレクトリ配下にコマンドをインストールする。
bundle binstubs ruby-ide-debug bundler
launch.json
内では、予め用意された変数を使ってパスなどを生成することができる。
ここで、VS Codeが開いているワークスペースの絶対パスを表すworkspaceRoot
を使い、先程のpathToRDebugIDE
とpathToBundler
の値を指定する。
具体的には、デバッグのためにRailsサーバーを起動する設定は、以下のようになる。
{ "name": "Debug Rails server", "type": "Ruby", "request": "launch", "cwd": "${workspaceRoot}", "useBundler": true, "pathToBundler": "${workspaceRoot}/bin/bundle", "pathToRDebugIDE": "${workspaceRoot}/bin/rdebug-ide", "program": "${workspaceRoot}/bin/rails", "args": [ "server", "-p", "3000" ] }
同様に他の設定についても、pathToRDebugIDE
やpathToBundler
の値を置き換えていく。
一通り置き換えてみたものがこちら。
https://github.com/satoryu/ChatterBox/blob/master/.vscode/launch.json
他のレシピも良さそうなので、機会があったら試してみたい。
Agile Japan 2019サテライト 新横浜 に参加してきた。 #agilejapan #デンソー
Agile Japan 2019の企業内サテライトの1つである、デンソー(新横浜)会場に参加してきました。
#agilejapan 新横浜サテライト、始まる! pic.twitter.com/hAR5ayDhfs
— さとりゅう 🌸 たつや学院 (@sato_ryu) August 13, 2019
Agile Japan 2019の基調講演はとても興味があったのでその動画を観れる良い機会でしたし、普段同じ建物で仕事している人たちと*1一緒にOSTしたりと、楽しい時間を過ごすことができました。
基調講演
LOVOTを開発しているGroove X株式会社代表取締役の林さんの講演を視聴しました。
- ロボット開発はハードウェアとソフトウェアの両輪の開発
- 新規事業
という点で、新横浜でのMaaS開発と近いものを感じていたので、非常に面白い内容でした。 気になったところをサラッと書きます。
- 先が見通せないからこそスクラムで、なおかつ組織の体制も階層構造をやめてフラットにしている。フラットにして、複数チームが勝手に独立して動くような船頭が多い状態ではなく、そこを引っ張れるだけのプロダクトオーナーが必要そう
- 「失敗を早くする」といっても盛大にずっこけることはできないので、リカバリや損切りを判断できるスキルが必要そう
- 「飽きる」という感覚をポジティブに使うこと。新しいことへ挑戦するモチベーションの現れでもあるので、挑戦にもつながるが、それだけでなくそこに対応できれば離職率を下げられそう。実際に離職率が2%程度とおっしゃっていた。
個人的には、さらっと「100億溶かした」とか言っていて、それだけしてでもやりたいと思える情熱がプロダクトオーナーには必要なんだろうな、と勝手に頷いておりました。
基調講演後の感想戦
基調講演を観ている時に、各自で気になったところや感想を付箋に書き留めていたものを全員で共有し、特に気になるところについてディスカッションしました。
- フラットな組織って?
- 組織がフラットになると、2:8の法則の2割がなくなるってほんと?
- うちらって「洞窟」っぽい?
みたいなことを、ときには脇道にそれたりしながらワイワイと話をしました。
ランチセッション
社内Slackで「どんなセッションをやりたいか?」を公募したところ、「焼きそばを作る」「焼きそばを食べる」という2つがエントリーしており、これが採択されました。 ということで、ハードウェア(ホットプレート)とソフトウェア(焼きそばの材料など)の調達からリリース(調理)まで自己組織的に行いました。
新横浜サテライトの現場からです。#agilejapan pic.twitter.com/qQd8O1eynz
— さとりゅう 🌸 たつや学院 (@sato_ryu) August 13, 2019
焼きそばを焼くワークショップ#agilejapan #デンソー pic.twitter.com/GpYVXVlMi5
— TAKAKING22 (@TAKAKING22) August 13, 2019
ランチセッションが終了。
— さとりゅう 🌸 たつや学院 (@sato_ryu) August 13, 2019
※ 料理はスタッフが美味しくいただきました。 #agilejapan pic.twitter.com/8bxya1dD1U
再演: 大企業をリファクタリングしてみる
Agile Japan 2019で登壇した弊社石田さんの再演。 いままでチラッと聞いたことがある、Joy, Inc を参考にした自分たちの秘密基地づくりやインナーソースの取り組みについて聞けたのはとても良かった。 組織と人をハードウェアとソフトウェアのアナロジーで見直すことで、得られる考え方も変わってくる。新しい改革プロジェクトって立ち上がるけど、人が集まらないというのはどこにでもあるもんなんだな、と。
石田さんの講演資料はこちら。
OST
OSTが何かについては、先日優良コンテンツが出たのでそちらをご参照ください。
せっかく同じイベントに参加してるのだからもっとワイワイと話さなくちゃ! ということで、やってみたところ、短い時間の中でカバーしきれない話題がたくさん出てきました!
答えは出なくても、普段モヤモヤっとしてることを出してみて、思考を整理したり、他の人の意見を聞けたり、新しい情報を得られたりできるので、こういう時間はとてもいいですね。
ちなみに、引き続きオススメ映画(Amazon プライムで観れるもの)は募集中です。
Fun! Done! Learn!
楽しい時間は過ぎるのが早いというもので、その楽しさをFun! Done! Learn!で振り返りました。
今日のFun Done Learn#agilejapan #デンソー pic.twitter.com/y9ZQPUhtUD
— TAKAKING22 (@TAKAKING22) August 13, 2019
おわりに
7月に入社して、まだ右も左も分からない感じなんですが、大企業だけどポジティブに色んなことをやっていこうとしている人たちがいる感じがしました。 しかし、良くも悪くも皆さん真面目な空気を感じてもいます。
今日みたいな楽しいことが普段からやれていけるといいな、と思った次第です。 これからも楽しむぞ!
Railsでウィザード形式のフォームを実装する時はテーブルを分けよう
ユーザーへの入力を便利にしようと、ウィザード形式を採用しようと思って、試しに雑に作ってみた時にハマってしまった。
例
実際のコードは晒せないので、サンプルとして以下のような状況を考える。
例えば、プロフィールサービスを作っていて、ユーザー登録後にユーザーのニックネームやアバター画像、TwitterやFacebookなどSNSのアカウント情報を入力させたくて、ウィザード形式を採用しようとしている。とする。
ここで、プロフィール入力を2ステップで構成されるウィザード形式にしたい。
- ニックネームと誕生日を入力
- 各SNSのプロフィールのURL
また、各プロフィールは必須入力としたい。
当初はウィザード形式は考慮していない実装だったので、ユーザー登録後に入力する情報は、いずれもユーザーのプロフィールということでprofiles
テーブルに登録する。
テーブルのスキーマは以下のようになる。
ActiveRecord::Schema.define(version: 2019_08_11_000716) do create_table "profiles", force: :cascade do |t| t.string "nickname" t.date "birthday" t.string "twitter_profile_url" t.string "facebook_profile_url" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["user_id"], name: "index_profiles_on_user_id" end create_table "users", force: :cascade do |t| t.string "email" t.string "password_digest" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["email"], name: "index_users_on_email", unique: true end end
良くない実装
必須入力の項目のチェックするために、Profile
モデルにバリデーションを設定する。
class Profile < ApplicationRecord validates :nickname, presence: true validates :birthday, presence: true validates :twitter_profile_url, presence: true validates :facebook_profile_url, presence: true end
これだけだと、ウィザードの最初のステップでニックネームと誕生日を入力し、その時点の情報をprofiles
に保存する時にその後に入力するtwitter_profile_url
などのバリデーションによって止められてしまう。
validates
メソッドのon
オプションで、そのバリデーションを有効にするタイミングを制御することができるので、それを使うことで一応は解決できそうではある。
class Profile < ApplicationRecord validates :nickname, presence: true, on: [:step1, :step2] validates :birthday, presence: true, on: [:step1, :step2] validates :twitter_profile_url, presence: true, on: :step2 validates :facebook_profile_url, presence: true, on: :step2 end
このようにしておけば、モデルを保存する時に、save(context: :step1)
などとすればステップごとに有効にしたいバリデーションを指定できる。
問題点
on
オプションでバリデーションを追加すると、指定されたコンテキストでしかバリデーションが実行されないので、通常のsaveやupdate時にも有効にさせたい場合との区別が難しい。
このウィザード以外にProfile
を保存や更新する場合に、必須入力であるということがチェックされない。チェックするにはコンテキストを指定する必要がある。
良さそうな実装
profiles
テーブルを分割する。
そもそもウィザード形式で分ける時に、各ステップでの入力項目には意味がある単位にわかれているはず。そうでなければ、何の入力の助けにもならない。
ということで、ニックネームと誕生日、TwitterとFacebookのURLとそれぞれの組でテーブルを分ける。
ActiveRecord::Schema.define(version: 2019_08_11_134450) do create_table "profiles", force: :cascade do |t| t.string "nickname" t.date "birthday" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["user_id"], name: "index_profiles_on_user_id" end create_table "social_profiles", force: :cascade do |t| t.string "twitter_profile_url" t.string "facebook_profile_url" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["user_id"], name: "index_social_profiles_on_user_id" end create_table "users", force: :cascade do |t| t.string "email" t.string "password_digest" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["email"], name: "index_users_on_email", unique: true end end
当然だが、こうするとバリデーションは普通の記述になる。
class Profile < ApplicationRecord belongs_to :user validates :nickname, presence: true validates :birthday, presence: true end class SocialProfile < ApplicationRecord belongs_to :user validates :twitter_profile_url, presence: true validates :facebook_profile_url, presence: true end
おわりに
ウィザード形式を採用する場合に、テーブルを意味のある単位に分割することでバリデーションが複雑にならずに済む。 データの設計がコードに影響することがわかる例だと思う。
分割することで悪い影響はまったく無いのだろうか。
1つあるとすれば、分割されたテーブルの情報を使ってユーザーを検索する場合にJOINするコストが発生することくらいではないだろうか。
例えば、上の例で、social_profiles
テーブルのtwitter_profile_url
とprofiles
テーブルのname
をusers
テーブルのSELECT文のWHERE句で使う場合だ。
2つのテーブルくらいなら大丈夫そうだが、増えていった場合はパフォーマンスの影響も考慮した分割の方法を検討すると良いのかもしれない。
また、既に稼働しているサービスの場合、分割に際してデータ移行が必要となる。
参考
2年前くらいに読んだ「システム設計の原則」の中で似たようなことをやっていたのを思い出したのがきっかけ。 あらためてその部分を読もうと思ったのだけど、失くしてしまったのか、後輩にあげてしまったようなので、また買うかな…
現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法
- 作者: 増田亨
- 出版社/メーカー: 技術評論社
- 発売日: 2017/07/05
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
Google AssistantのバックエンドをAzure WebAppで作った。
Google Homeで音声を入力とした何かを今後作るかもしれないので、試しにGoogle Assistantを作るためのActions on GoogleとDialogflowを使った開発をしてみた。
初めて触れる技術のことなので、アプリケーションのネタはとてもシンプルにこれまで作ってきた駄洒落の自動生成にした。 で、実際にできたものがこちら。
バックエンドを、Firebase Functionsで作ろうと思ったのだが、無料版だと外部へのネットワーク接続ができないため諦めた。バックエンドは、Webhookの呼び出しを受けられれば何でも良いので、今回は普段から慣れているAzure WebAppを使うことにした。本当は、Azure Functionsにしたかったのだが、npmパッケージのactions-on-google
がサポートしていなかったので、WebApp上で動くnode.jsアプリケーションとして作った。
ソースコードは、こちら。
ユーザーの認証や、リソースへのアクセス権限を取得したりできるようなので、できることは色々ありそう。
インスタンス名を取り締まるためのRuboCop拡張をリリースしました。 #rubocop
インスタンス名を取り締まるためのRuboCop拡張 rubocop-instance_variable_name
をリリースしました。
何ができるの?
この拡張がやっているのは、とてもシンプルなことで、インスタンス変数名の長さが一定以下(デフォルトだと2)のインスタンス変数に警告を出します。
@ms = 'foo' # bad code @message = 'foo' # good code
作った動機
最近、他人の書いたコードをレビューしたり、他人の書いたコードを修正する機会が増えてきました。
その中で、いつも悩まされるのが変数名がわかりづらい時でした。
特に、インスタンス変数名は重要だと思います。
メソッド名やattr_reader
などで定義されるゲッターが分かりづらかったり、複雑なコードだとしても、変数名が何を表しているのかがわかると読み解くことができます。
特にクラス変数名は重要です。
読みづらさの中で最も辛いのは、略語を使ったものです。 普段使わない単語を使っているのも読みづらいのですが、英和辞典やググれば理解することはできます。 ですが、略語になると、それを推測するのが非常に難しくなります。
ということで、インスタンス変数名の長さに注目し、受け入れられない長さの変数名を指摘するRuboCop拡張を作りました。
是非ご活用ください。 また、何か不具合等ございましたら、Issueを作っていただけると助かります。