めるノート

Web界隈で生きる。

『THE TEAM』×『エンジニアリング組織論への招待』コラボイベントに参加しました

先日、以下のイベントに参加しました。

connpass.com

ブログ枠で参加したのに、投稿が遅くなってしまってすみません!
実は「THE TEAM 5つの法則」本編を読むのがイベント後になってしまった(死)のですが、イベントと書籍についての感想を書かせていただきました。
もし「書きすぎ!」とか「それはちがう!」みたいなところがあれば、遠慮なく自分(@c5meru)までご連絡いただければと思います!よろしくお願いします。

イベントの冒頭で「何か決まった手段をとればマネジメントができるという思い込みが失敗の元である」という言葉があって、これは本当にその通りだな、と思いました。自分は日頃から、手法にこだわりすぎないように意識しています。

Aim(目標設定)の法則

こちらはイベント会場では???だったのですが、書籍に書いてある例がとてもわかりやすかったです(そもそも書籍を読んでから来る前提のイベントなので当たり前ですが...)。

本を売る時の目標の立て方の例(書籍内での例)

  • 行動目標: 事例を交えて分かりやすく伝える本を作る
  • 成果目標: 10万部売る
  • 意義目標: 日本全体のチーム力を高める
  • OKRの「Objectives」が意義目標、「Key Results」が成果目標

イベントで話されたこと

  • 意義目標
    • 学校では教わらない
    • OKRで定められる
    • 抽象と具象の行き来をするのはトレーニングしないと大変
      • メンバーのレベルに合わせてやっていく
      • ジュニアなメンバーだと意義目標を立てるのは難しい
  • 成果目標
    • 数字を出すなど
    • OKRで定められる
  • 行動目標
    • 学校でやるような目標
      • あいさつをする
      • 忘れ物をしない
    • 環境の変化が少ない場合にワークする
    • 最近の企業は変化が多いのでワークしなくなってきた

書籍では、それぞれにメリット・デメリットがあるので、適切に設定することが大事とありました。
ですが、実際の現場では意義目標が欠けていることが多いそうです。自分の身の回りでもそのように思います。
「何のためにやっているのか」ちゃんとわからないまま走っていることが多いです。


Boarding(人員選定)の法則

こちらの説明は、本よりも、勉強会の場でガーッと説明されたほうがわかりやすかった印象がありました。

環境の変化度合い

  • 体が触れるスポーツは、相手の動きを気にしなくてもいい
  • 環境の変化度合いが高いチーム
    • 流動的なチームにした方がいい
    • 環境の変化によって入れ替えた方がいい
    • 採用で絞るのではなく、ある程度は誰でもいれて、合わない人が退職などの、入れ替えを考慮する
    • 必ずしも退職は悪いことはない、適切に循環すれば
  • 低いチーム
    • 固定的なチーム、退職は良くないかも
    • チームの入り口で厳選すべき

人材の連携度合い

  • 同じ時間に味方とフィールドで動くかどうか
  • 連携度合いが高いチーム
    • 異なるタイプ、多様性の高いチームにする
  • 低いチーム
    • 均質性の高いチームにする
    • 似たタイプを揃える

両者の度合いの大小で4つのタイプに分けられる

  • 駅伝型(環境の変化度合いが小さく、人材の連携度合いも小さい)
  • 野球型(環境の変化度合いが小さく、人材の連携度合いは大きい)
  • 柔道団体戦型(環境の変化度合いが大きく、人材の連携度合いは小さい)
  • サッカー型(環境の変化度合いが大きく、人材の連携度合いも大きい)

どんなビジネスモデル、どんな価値観の中にいるのかによって、どんなチームが向いているのかを考えるのが大事とのこと。

異なる価値観のチーム間では文化摩擦が起きやすい

  • 柔道団体戦のような営業チームに多い組織だと、目標を数値にしたり、目標を個人に設定させたりしがち
  • スタートアップだと中途入社のメンバーが前職の制度と比べがち
  • THE TEAMが、互いの理解を深めるためのヒントになれば

イベントでは、今どんなチームにいますか?という話がありました。

前はフルスタックエンジニアが1人1プロジェクトをもっていたのですが、現在は数人で同じプロジェクトをやったり、プロジェクト間のデータ連携があったりするので、以前とは違う体制が求められているな、と感じています。

また、チームの入口(採用)と出口(退職)にどのくらいこだわるべきなのかは自分もモヤっとしていた部分があったので、今回これを見てスッキリした気持ちがありました。


Communication(意思疎通)の法則

イベントではあまり言及がなかった部分です。
前の「Boarding(人員選定)の法則」で語られたチームのタイプに応じて、Communicationにおけるルールを適切な粒度で設定する必要がある、という話でした。
同様に、

  • 責任範囲
  • 評価対象(成果を評価するのか、プロセスを評価するのか)
  • コミュニケーションの頻度

もチームのタイプに応じて適切に設定すべきということでした。
他にも、コミュニケーションやチーム作りにおいて大切にすべきポイントなどが書かれています。

具体的にどのように設定すればいいのかについては、あまり書きすぎてもアレなので、書籍の方でお楽しみください!


Decision(意思決定)の法則

まずは意思決定の仕方を意思決定すべき、という話があり、なるほど!と思いました。

意思決定の3タイプ

  • 独裁
    • 納得感が低い、すぐ決まる
  • 多数決
  • 合議
    • 納得感が高い、なかなか決まらない
    • 最近はスピード感が求められるので最終的には誰かが決めた方がいい

それぞれにメリット・デメリットがあるので、企業のフェーズ等に合わせて適切に設定するのが大事ということでした。

イベントで話されたこと

  • THE TEAMでは3〜10人をチームと定義している
  • 決まらなくて組織が腐っていくことが多い
  • 決めることが怖い人が多い
    • 責任が曖昧、失敗したらやめないといけない感じ
    • その責任をうやむやにするための合議になってしまっている
    • エスかノーか決まらないままになっている会社が腐っていく会社である
    • 即時の意思決定力が低いマネージャーは能力が低いことが多い
      • 即時の意思決定のトレーニングをするべき
      • 早く決めたチェスの手と、考えて決めた手は86%同じ
      • 早く決めればやり直せるから正解に近づける

上記に書いた通り、以前@magnoliaさんに1on1をしていただいたのですが、その時に話したことと同じことが話されていました。
magnoliaさんは某大手IT企業のスーパーマネージャーなので、規模などに関係なく、やはり決めることって大事なんだな、と実感しました!


Engagement(共感創造)の法則

こちらも、イベントではあまり言及がなかった部分です。
「気合ではない方法で、メンバーのモチベーションを上げるには?」という話で、あまり感情的な話が得意ではない自分にとって非常にありがたい話でした。
こちらも、あまり書きすぎてもアレなので、書籍の方でお楽しみください!


まとめ

THE TEAM 5つの法則」の冒頭に、『チームをチームたらしめる必要条件は「共通の目的」』とありましたが、現職で自分がみているチームはこれを利用して「インフラチーム」とし、馴れ合いがなくても協力できるような体制になっていきました。
その他にも、自分がこれまでの部活・サークル・会社などを通した経験の中で感じたこと、やってきたことなどが、たくさん言語化されて散りばめられていたので、読んでいてとっても楽しかったです。

この本を読んで、いろんな法則について「じゃあウチはどうだろう?」って、周囲の(特に社内の)人とたくさん話をしてみたくなりました!これ読んでるかわからないけど、関心のある人だれか話そうよ!

素晴らしい本を書いてくださった麻野さま、冒頭のイベントを企画してくださった、リンクアンドモチベーション社とレクター社の皆さま、ありがとうございました!

アイコン缶バッチのすゝめ

おもしろいので、アイコンを缶バッチにしてみました。

RubyKaigiより前から持ち歩いていて、勉強会などで見えるところに着けるようにしているのですが、これが結構便利です。
よく、オンラインゲームみたいにハンドルネームやアイコンが頭上に出れば良いのにねー、なんて話がありますが、それを手軽に実現できている気がします。
RubyKaigiでは、インターネットだけで知り合っていた方と数人お話しすることができました。

作成したのはGMOペパボさんが運営するSUZURIです。
缶バッチを買うと考えるとちょっと高いですが、オリジナルが1個から作れるのは非常に魅力的です。

ちなみに、カバンも作りました。

髪が短い方はRubyKaigi翌日の観光中に紛失したんですが、SUZURIならすぐに再購入できるので楽です。

RubyKaigi に初参加してきました

Ruby3年目にして初めての RubyKaigi に行ってきました。とても楽しかったので、来年も身軽だったら参加したいと思いました。
キーノートのレポートは追って会社ブログにあげる予定なので、ここではセッション以外の話を箇条書きしていきます。

知見

  • 朝早めに行って公式ノベルティをもらわないとTシャツのサイズがなくなるらしい
  • スポンサーのノベルティも早めに回らないとなくなる
  • 荷物は少なめがよい
  • 飲み会が川で行われるらしい
  • カラオケではジャンル別に部屋ができるらしい
  • partyをしっかりチェックして、ちゃんと夜の予定を定めるべし
    • 前夜祭の船とコード懇親会、面白そうだったけど埋まっちゃってた
  • 飛行機のチェックインは早すぎるくらいがちょうど良い
    • 行きの飛行機がかなりギリギリになってしまった

よかったこと

エモリハウスに突撃した

  • エモリハウス
  • ぼっちにならない
  • 一方で団体行動もきつくない
    • 17人もいると、いつも全員で、という感じは一切ない
  • 行く店が全部おいしい
  • 無限に日本酒が飲める
  • エモリさんの顔が広いので、有名人とたくさんエンカウントできる
  • 4泊5日でめっちゃ安い

ノベルティが豪華だった

  • スポンサーも多かった
  • ノベルティをひと通りもらうと3kgあるらしい
    • クラウドワークスさんのPC台が結構重いんだけど、可愛いし便利そうなのでついもらってしまった
  • それでも全部欲しい
    • かわいいし便利だし豪華だし
  • スタンプラリー40カ所まわってキーケースもらった
  • JapanTaxiで、人事の人だと気付かずk8sについて質問してしまったので申し訳なかった
  • 三木さんと久しぶりに話せて嬉しかった

note.mu

会場ロケーション

  • 海が綺麗
  • ランチ時間で散歩できる

カンファレンス運営の学び

  • HTML5もVueもスタッフ参加の経験しかなかったので、大規模カンファレンス一般参加は初めて
  • 同時翻訳すごかった
  • ゴミ箱がいっぱいあった
  • 座るところもいっぱいあった
  • スポンサーブースの設置時間
  • 地方カンファレンスは、大人数のオペレーションがやりやすそう

Rails Girls

  • 今まで特に縁もなかったし、知り合いも繋がりがなかったRails Girls
  • バックエンドの国際カンファレンスなのに女性比率が高いことにびっくりした
    • しかもRails Girls関係者が多いような気がした
  • 日本各地のつながりが強い
  • 子育てする女性、年上の女性のロールモデルがたくさん
  • 無意識のうちに不安になっていたけど、この業界でやっていくイメージが具体的になった

コミュニティにいる人それぞれの生き方

  • スタッフじゃない常連が活躍するかどうかがコミュニティの肝
    • エモリさんをはじめ、エモリハウスのRubyKaigi経験者は素晴らしかった
    • スタッフや関係者と、一見さんをつなぐ非常に重要な役割となっていた
  • 有名企業に勤めるエンジニアだけが優秀なわけじゃない
    • 当たり前のことだけど最近は見失っていた
  • コードを書くことで活躍する人、コミュニティで活躍する人、さまざま
  • 仕事ではなくても、好きなコードを書いて幸せに暮らしている人がいる
    • わたしの好きなコードは何だろう、最近は忘れていた気がする
  • 自分なりの生き方を見つけていこう

エンジニアリングマネージャーでいるのがつらくなったときは

そういうときがよくあります。
マネジメントを仕事にしたのは今の会社が初めてだけど、きっとこれから先も会社に所属している限りは、なくならない気持ちなんだと思います。
だから、そんなときに振り返れるようなものを残しておきます。

...時が経つのは早いもので、コードレビューを受けるのがつらかったわたしも、気がついたらチームリーダーになっていました。
今では、当時自分自身が書いた記事を読んで、レビュアーとして考える日々を送っています。

煽りタイトルで申し訳ないのですが、マネジメントを始めてまだ1ヶ月しか経っていません。
けれど、なんとなく、

  • コードを書く時間が減ってしまったことに対する不安
    • 自分は何も生産していないのではないか
    • 今後のキャリアどうしよう?
  • 職場の人間関係に対して常にアンテナを張っていなければいけない気がする不安
    • Slackから目が離せない
    • あそこで話している人たち、何を話しているのだろう?

こんな感じで、うっかり夜遅くまで残業することになってしまったり、やや寝不足ぎみになってしまったり、なんとなく胃腸の調子を崩したりしています。
それが自分だけならまだしも、どうやら他のリーダーも遅くまで残業したり、どこか顔色が悪そうだったりするのです。
もしかして、こうして悩んでいるのは自分だけではないのかもしれないと思い、約1年ぶりに「つらくなったときは」というタイトルで記事を書くに至りました。

特につらいこと

自分は幸いなことに、そういう機会が巡って来ることは今のところないのですが、周囲の話を聞いているとマネジメントのお仕事で一番つらいのがこちら。ネガティブメンバーのマネジメントだそうです。

i47.hatenablog.com

現状

自分がチームリーダーになってからのスタンスは、以下の記事に近いです。ちなみにこの翌日のアドベントカレンダーがリアル上司ですw

takaking22.com

社内の人に読まれていそうなのですごく書きづらいんですが、特に、なるべく「情報を筒抜けにする」のは、やってみてかなり良い感じです。メンバーとの距離も広がらないですし。

そして自分を取り巻く現状としては、以下の記事が近いです。たぶんお会いしたことのある方の記事です。

kobakei.hatenadiary.jp

いかんせんコードを書くことの成果が見えやすいので比べてしまうのですが、ここで出てくる 「エンジニアの生産性」って、どうやって成果としてはかるものなんだろう? と最近は疑問に思ったりもしています。

よく言われる「プレイヤーとして優秀なエンジニアが昇給していくためには望んでないのにマネジメントにならないといけない」問題の対策として、マネジメント系のキャリアパス以外にもエキスパート系のキャリアパスを定義し、「それぞれのキャリアパスの各グレードってどういう役割が期待されているんだっけ」などと考えて設計しています。

ここは最近、自分も部署内で問題提起をしました。
だって、昇給したくてマネジメ(自主規制
というのはおいといて、わたしはこうあるけれど、チームメンバーにはエキスパート系のキャリアパスを早く見せたいな、と思っています。

悩みは「悩みを言えないこと」

先の記事の「意識低い系」スタンスで、けっこう悩みを言ってしまうことは多いです。でもやっぱりあんまりよくないなあ、と最近は思っていて、チームリーダーだけで話し合う場を設けたり、他の部署との交流を増やすなどして工夫しています。

あとは採用ですね。「一番大事なのは採用」と記事にもあるとおり、マネジメント難易度を下げるための採用、したいです。。

今の自分にはなかった考えがあった

この記事を書くにあたり、例によって「チームリーダー つらい」とか「エンジニアリングマネージャー つらい」とかいうググり方をしたわけですが(笑)、そんな中で新しい発見もいくつかありました。

toyokeizai.net

上記の記事は2ページ目から「退職を伝える前に試してみること」がいくつか上がっているんですが、

  • 仕事のやり方をパクる
  • チームメンバーの個性を知る
  • 準備をする

あたりは自分も意識している一方で 「助けを求める」 という案はなかったな、と思いました。
先述の通りわたし自身にも上司がいるので、あまり抱え込まずに頼ってもいいのかもしれません。

次に、以下の記事です。

geechs-magazine.com

この 「マネージャーになると起こる変化」 の中で自分が「おっ」と思ったのが以下です。

  • 技術の習得範囲が広がる
  • 非エンジニアとのコミュニケーションが増える

マネージャーなのに技術の習得範囲が広がるのはすごく不思議なんですが、マジです。
自分は最近インフラまわりを勉強しているんですが、たまたま自分のチームにインフラが得意なメンバーがいたり、自分と同じようにインフラ勉強したいって思っているメンバーがいるので、一緒に勉強している感じがして楽しいです。まあ、あっという間に自分だけ置いていかれちゃうんでしょうけどw
あと、チームメンバーのインフラの設計レビューに出ることもあるんですが、CTOが直々に出てきてハイレベルなやりとりが見れるのも(傍観者だからというのもあり)ちょっと楽しいです。傍観者だけど、事前に自分も必死で予習しました。笑

非エンジニアとのコミュニケーションが広がるというのは、コミュ力のある方ならマネージャーにならなくともできるかもしれないのですが、規模の大きな企業になってくるとなかなか難しかったりします。
リーダー同士での会話や、リーダーのみが対象になるイベントは、大きな企業の中でも比較的優秀なメンバーが集まってやることが多いので、お互い話してみると普通に面白かったりします。

わたしの理想

個人的には、こういう感じが理想です。タイトルがアレですがw

eri-twin.hateblo.jp

最初に出てくる、こういうリーダー、ほんとうによく見ます。

リーダーはただのスーパーマン。 要件からバックログのタスクにする。調整して、みんながタスクに集中できる環境をつくってあげられる。コード書いてタスクを燃やせる。なんでもできる。リーダーすごいよ。

なんでもできるのは確かに良いことなんですけど、この記事にあるような「リーダーに甘えていたボンクラコーダー」を生み出すような人はチームビルディングできない人なんだな、と思います。なので、そうならないように意識はしているつもりです。

「プロジェクトの目的のために行動できる人になる」のは、リーダーだけじゃいけない

こういう話は他の記事でもありまして、

developers.freee.co.jp

上記のfreeeさんの記事ではCTOみずから新卒のメンバーに 「3年間でスモールチームのCTOになってほしい」 と伝えていますし、

www.m3tech.blog

上記の記事はエムスリーさんですが、実際にCTOを任せちゃってます。

マネジメントはやりたくなかったわけじゃない

わたし自身、本当に昇給のためにマネジメントを始めたのかというと、今のタイミングだけ見たらイエスなんですが(笑)、そのうち子供ができて、生まれて、子育てして、それを2人か3人くらいやって、本格的に復帰して現場にコミットできるようになった段階では、どのみちもう一度やろうと思っています。今のところ。

以下の記事にもあるんですが、

qiita.com

機械を直接相手にする必要はなくなりますが、チームの価値を最大化するという課題にたいしエンジニアリングすること自体にかわりがない

この通りでして、たしかEM.FMの第1回かな?同じような話を広木さんあたりがされていた記憶があります。

大学時代オーケストラサークルにいたときに、どうやったら効率よくメンバーに動いてもらえるんだろうって思って、マネジメントとか、心理学に関する本を読み漁って、トライアンドエラーを繰り返していた時期がありました。
そういうのもあって、どうやら自分は他人よりもその手のスキルがあるらしい?と思うこともあるのですが、単にエンジニアの中にいるからかもしれません。

ただ、今のタイミングではもう少し技術力を強化したい気持ちもあって、その間で揺れてしまうことも多いです。
エンジニアのためのマネジメントキャリアパスという本の5章でも、以下のようにあります。

いきおい管理者は経営と人的管理に関する職務に忙殺され、仮に技術的な作業に時間を割こうとしても夜間か週末しかない、ということになります。自分の会社がこういう企業なら、「コードの作成やシステムのデザインはもう十分マスターした」と得心するまでは技術力の強化に専念し、納得がいった時点で初めて経営系に舵を切るか否か判断するとよいでしょう。いったんコードを書く作業から遠ざかってしまうと遅れを取り戻すのが大変です。機が熟する前に離れてしまうと、中間管理職より上に昇るのに必要な技術力を十分身につけられずに終わってしまう恐れがあるのです。

いつだってプレイヤーに戻れる

先に紹介したエンジニアのためのマネジメントキャリアパスの3章には、こんな文章があります。

あなたが望めば進路変更も可能だ、ということを忘れてはなりません。ある時点で管理職に就いてはみたが、やはり自分には向いていないと判断し、技術畑に戻る人も少なくありません。どちらの選択肢も決して恒久的なものではないのです。いずれにしても常にしっかり目をあけていること。どちらの道にもメリット、デメリットはあり、どの仕事が一番自分に向いているかを見定めるのはあなた自身なのです。

わたし自身、この文章にすごく救われました。
今日も、他の部署の方と話している中で「戻ったって良いんだよ、そうしたいと思ったら伝えてごらん」と言ってもらうことがありました。ですので、つらくなってしまったときも過度に悲観的にはならないでいたいな、と思います。

また、以下の記事では、えふしんさんが「エンジニアリングマネージャは入れ替わっても良い」と述べています。

devblog.thebase.in

そして、ここからが大事なことですが、必ずしもエンジニアリングマネージャは永遠にその立場でいる必要もなく、一定期間で別の人に入れ替わっても良いと考えています。期待するのは大人としてチームの活躍を支えるチームディレクションとしての役割です。ディレクションかプレーヤーかというのは、その都度、役割を入れ替えることはあってもよいと思います。

なによりそうすることで、たくさんのエンジニアが人の成長を支える仕事の難しさを知ることができるし、一度、エンジニアリングマネージャを経験した人は、より広い視野での仕事を期待できるわけなので、改めて現場でコードを書く役割にコミットしながら、開発プロジェクトマネジメントやメンバーの育成においてもエンジニアリングマネジメント力を発揮することが期待できます。

そうこうしてるうちに新しい事業アイディアが出てきた時には、そういう人が率先してエンジニアリングマネージャとしてチームを作れるようになることで組織のスケーラビリティは向上します。

このようにエンジニア組織全体としては、立場を入れ替え可能であることと、マネージャという役割をエンジニアとしてのキャリアの幅や柔軟性を高める役割として定義することで、プログラマ35歳定年説に代表されるような、コードを書かなくなって、エンジニアとしての死を迎えるみたいな不安な世界を終わらせることができるのではないかと考えています。

まとめ

マネジメントを任せてもらえるというのは信頼されている証しで、成長している証しです。そしてきっとマネジメントという仕事を通して、エンジニアとして技術的にも人間的にも、もっと成長できることがあるはずです。いっぽうで、コードにコミットできる今だからこそ手を動かしてスキルを伸ばしたい!と思うこともあります。
まあ、マネジメントはやりたければいつでもできるという話でもないので、もうしばらく、この貴重な機会を味わっているつもりです。

余談

...という日々を過ごしている中で、そういう気持ちをもっともっといろんな人とお話ししたいので、サイゼリヤミートアップをしようと思いconnpassで下書きまで作ってあるんですが、予約できるサイゼリヤが見当たらなくてできないでいます...!
もう普通の居酒屋でやろうかなあ。

わたしのオススメ技術書

今日会社で「なんかいい本ないですか?」と聞かれて、オススメ本リストを作りました。
前提としては Rails × Vue をメインに開発している会社なので、他のバックエンド・フロントエンドの情報はない感じです。。

オススメ本って人によって違うので、幅広いジャンルを心がけました。
未読のものもあるのでなんとも言えませんが😅、せっかくなので、ここに残しておこうと思います。

反省としては、Railsに関する本、Vanilla.jsに関する本、データベースに関する本、インフラに関する中級者以上向けの本を知らないんだなあ、わたし。と思いました。
特にDBとインフラは、もうちょっとがんばらねば。

あとから思い出したら黙って追加してるかもです。


Web全般

設計

インフラ

Ruby

デザイン

Vue.jsなど

外部サイトにリダイレクトするときは、オープンリダイレクトに注意しよう

すごく当たり前の話なんですけど、最近うっかりやってしまったので反省文として書きます。

まだリリースしていないサービスの初期実装で、現在のURLをパラメータにとって、ログインしたらリダイレクトで戻ってくる処理を作りました。

サービスにアクセスした時、ログインしていなければ、以下のアドレスにリダイレクトされます。
redirect_uri パラメータの中身は、最初にアクセスしたURLになります。

https://www.example.com/login?redirect_uri=https://www.example2.com/

ここで、普段おとなしい同僚から、こっそり声をかけられて、危険ですよ、というアドバイスをいただきました。
実際、作っている時もなんか危ないな、という気はしていたのですが、具体的に何かは思い出せなかったのでした。

そう、URLにある redirect_uri パラメータの中身って、なんにでも変えられちゃうんですよね。以下のように。

https://www.example.com/login?redirect_uri=https://www.cho-warui-site.com/

リダイレクト先をコントロールできてしまい、意図されていないページへのリダイレクトも許してしまいます。
これをオープンリダイレクトといいます。

オープンリダイレクトは、Webアプリケーション自体には問題がないように見えるのですが、たとえば、想定したリダイレクト先のサービスとデザインを似せたページを作って、ログイン情報を再度入力させることができれば、ログイン情報を盗み取れてしまいます。
こうしてフィッシング詐欺などに悪用される恐れがあるのです。
また、リダイレクト先を自由に設定できてしまうということは、HTTPヘッダインジェクションにもつながります。

なので、このようなリダイレクトをするときは

  • なるべくURLパラメータを使わず、リダイレクト先URLのホワイトリストを作って、そこから選ぶようにする
  • どうしてもURLパラメータを利用しなくてはならない場合
    • ドメイン名などパラメータの内容を正規表現等で厳密にチェックする(サブドメイン等も注意)
    • クッションページを設けて、外部サイトに行くよ!と注意喚起をする

以上のことを心がけるのが大切です。

いやはや、リリース前でほんとうによかったです。
今度、会社で徳丸本の輪読会をするので、きっちり読み返します。

参考 https://www.websec-room.com/2014/06/22/1899

「設計やチームビルドについて相談し合う会」に参加しました

参加したきっかけ

旦那さま(@polidog)や上司が参加するということで、こちらのイベントに参加してみました。 ハッシュタグ#dev_sodanでした。

symfony.connpass.com

Presented by 日本Symfonyユーザー会、ということで、自分はたまに社内プロジェクトでSymfonyのコードを読んだりはしますし、結婚するにあたってSymfony2入門を読んで写経したことはありますが、業務での開発はほとんど(Web制作会社でEC-CUBE3くらいしか)したことないんですよね。

しかし、ユーザー会の旦那さまいわく
「今回はSymfonyの話に限らず、表題の通り、設計やチームビルドについて話をするので、来ればいいじゃん」
ということで、参加させていただきました。ありがたや。

会場とか雰囲気

会場は五反田駅から徒歩圏内にあるサイボウズスタートアップスさんでした。

形式としては、15人ほどで輪になって座って、せたさん(@kseta19)の司会で、トピックひとつ30分程度を目安にディスカッションしていく感じでした。
最初は緊張しましたが、おそるおそる発言してもあたたかく受け入れていただける雰囲気だったので、とても楽しかったです。

ディスカッションの内容

会社を立ち上げたのだけれど、2人目のエンジニアが取れない

自分より技術力のある人を採りたい。
現在はツイッターのフォロワーを増やす活動をしており、勉強会の主催・会場提供もする予定。

  • うちは月に40〜50面接やってて、それで1〜2人くらい採用している
    • 2次では技術試験もやっている
  • うちはそんなに面接していないから、書類でめっちゃ落としてるのかも
    • ある程度ニッチな技術を前面に出して売り出した
    • 事業として最終的にどれくらいの数のエンジニアが必要なのか考えてみて
      • 最終的にあまりエンジニア組織を拡大しなくていいなら、ニッチを攻めたほうがいい
    • 2人目のエンジニアは自分より下の人しか取れないと思ったほうがいい
    • 自分たちの技術にふさわしいものはなにか?から考えたほうがいい
    • エンジニアの半分はリファラ
  • 勉強会に行って、出会ったエンジニアと飲みにいく
    • 難しいけど、伸び代のある人をとったほうがいい
    • 勉強会はスポンサーするのもアリだと思う
  • 自社でもくもく会を開いて、よく来る人を口説くとかよさそう
  • 業務委託の優秀な人に紹介してもらうのが良さそう
    • エンジニアにとって働きやすい環境を整えて、認知してもらうとか
  • うちが会社を立ち上げたときは、最初はたまたま成功報酬の媒体で取れた
    • その後は勉強会で会った人を口説いていった
    • 自分は経営とエンジニアの橋渡しを最高品質でやるCTOでいようと意識している

チームとプロダクトが増えたので、うまく情報共有ができなくなってきた

最近、急激にエンジニアが増えてきた。
各システムに分かれて開発をしているけれど、PM同士のつながりがなかったりして、連携している部分を共有できず見落としたりすることがある。
技術の知見や、開発手法もうまく共有できていない気がする。

  • うちは全部のプロダクトを自分(CTO)が見るようにしている
    • すぐに解決するのは難しいので、やっちゃいけないブラックリストを作ると良いかも
  • 実際はシステムが疎結合になっていないのに、チームが疎結合がなってしまっているのでは
  • うちではオフラインの会話が生まれやすい状況を作っている
    • カンバンで、困っていることを話す
    • 開発者がスタンドアップでみんな集まってやっている
  • 月1で報告会をやるようにしていた
  • 毎日6時になると立って、ビジネス側のメンバーも含めて夕会をしている
    • 規模としては15人くらい
    • また、みんなで社内システムを確認する会をしている
      • そこで一番社内システムを知っている人から、歴史的経緯や知らない部分を教えてもらっている
  • ドキュメントはメンテナンスコストがかかるからやめようっていう雰囲気になってる
  • ペアプロやモブプロをすれば、開発手法は共有できそう
  • 自分は、みんなで話すよりも1on1の方が話しやすいかも
    • どちらがいいかは、人によるのでは

新人にOOPを効率的に学んでもらう方法について悩んでいる

これまで「OOPオブジェクト指向プログラミング)ができること」を基準にエンジニアを採用していた。
エンジニアの採用が大変になってきたので、育成枠の採用を始めたいのだけれど、OOPを効率的に学んでもらう方法がないか悩んでいる。

  • イケてる(すぐ育つ)ジュニアエンジニアは、何であれ、すぐにできるようになる
  • うちは学生アルバイトの時給を高くしているので、イケてるアルバイトが取れていると思う
    • そもそもハイレベルな人を取った方がいい
    • 採用するときには、自分で勉強してるかどうかをまず聞くようにしている
  • なんでOOPが必要なのかを、まず教えないといけないのでは
  • うちは技術顧問などの強い人が、ペアプロでしっかりと見てあげている
    • 新卒だとまだ真っ白で我流がないので、いい感じに染まってくれると思う
    • ペアプロをして、ジュニアとシニアが二人三脚で、ひとつのものを開発するようにしている
    • 早い人は3ヶ月くらいでできるようになる
    • 新卒なら育てやすいと思うけれど、いい新卒は「すごいエンジニアと働きたい」と言って他社に取られてしまう
    • 入社して少し経ってから、こういう本を読んだらいいよってすすめる
  • まずは伸びる人を伸ばす、それが成功するとラクになってくる

レビュー地獄から解放されたい

レビュー地獄とは、自分がコードレビューを担当するエンジニアが多すぎるなどの原因により、レビューしなければならないPull Requestが多すぎて、コードレビューだけで1日をほとんど使い果たしてしまい、他の仕事ができなくなってしまうこと。

  • 先ほどの「まずは伸びる人を伸ばす」に通ずるけど、自分はレビューできる人を増やして、チームを分割した
    • 最近は楽になった
  • うちはコードレビューを担当するリーダーはいなくて、レビュイーがコードを見てもらいたい人に依頼する
  • うちは、くじびきでレビュアーを決めている
  • レビューに時間がかかるのは、その前に設計について相談していないからでは
    • プルリクエストで突然のRejectをくらわないようにちゃんと相談しよう
    • 自分の設計に対して不安に思っていれば相談するのでは
    • 相談しないということは、問題ない設計だと思っていたのでは
    • 設計を考える目的がシェアできているかどうか
  • うちは機能拡張するときに困らないように設計する、という考えがシェアされている
    • 本当に欲しいものは何なのか、長い時間をかけてビジネス側にきくようにしている
    • サービスレベルに影響するかどうか、影響するところは設計を含めてきっちり作っていく
    • 他のところはスピード感重視でやっていくので、リファクタリングデーを別途設けている

フロントエンドの設計をどうしたらいいのか分からない

  • props地獄がつらい
  • フロントエンドの設計には3種類ある気がする
  • そもそも、捨てるためのフロントエンドを作っていくべき
  • どんなテストを書くのが適切なのか
    • UIのテストはメンテが大変
  • Vue.js入門の後半に設計手法が書かれていてとても良かった
    • Atomic design
      • デザイナーの傾向として、このようなプログラマブルな考え方を受け入れない人が多いかも?
  • 後悔しないためのVueコンポーネント設計も良かった

まとめ

上記の他にも、自分からは「女性エンジニア(がチームにいることについて)どう思いますか?」というテーマをあげました。
燃えやすい話題なので詳細は省きますが(笑)、参加者のみなさんからいい話がたくさん聞けました。

また、全体的に、せたさんを始めとしたスタッフの皆さんがいい感じにディスカッションを進めてくださったので、非常に有意義で楽しかったです。

エンジニアとしてのキャリアが浅くて、まだまだ手を動かすエンジニアとしてやることがたくさんあると思っている身としては、「設計」と「チームビルド」というのは非常にハードルが高いトピックです。
だって、設計といえばマサカリが絶えず飛び交っていて怖いイメージですし(ひどい偏見)、チームビルドのようなマネジメント的な話は、(マネジメントも問題解決なのに)どうしてもエンジニアリングな話と対立しがちですから。

けれど、自分のフェーズがちょうど

  • 動くものは書けるけど、書いていて「この設計ではいけない」と思うことが増えたので設計の勉強をしている
  • チーム内のコミュニケーションで先輩っぽい振る舞いをすることが増えてきたので、全体最適を考えている

というのもあったので、ある程度長い経験をお持ちの「CTO」や「マネージャー」、「シニアエンジニア」などの皆さんと「設計」や「チームビルド」について非常に濃いお話をすることができて、ほんとうによかったです。ありがとうございました!

別々のdocker-composeに属するコンテナ同士で疎通させる

もう3ヶ月くらい前になるのですが、Dockerを雰囲気でやっていた自分が、ローカル上でそんなことをすることになりました。
当時の自分がこのタイトルを見ても「ハァ???」みたいな気持ちになったと思います。。。

dockerを理解するために読んだもの、読みたかったもの

最初の時点で、インフラに詳しいメンバーから
「たぶん network を設定するんだと思いますよー」
と言われていたんですが、とにかく自分はDockerについての知識が浅かったので、まずは docker-compose.yml が読めるようになるまで勉強してみました。

読んだもの

読みたかったもの

いろいろ勉強して解決した後に読んだけど、これを先に読みたかったw

booth.pm

booth.pm

docker-compose のnetworkについて

DockerとComposeの基本的なところを勉強したら、インフラに詳しいメンバーから教えてもらった network について調べつつ、疎通させる方法も一緒に調べていきました。

以下のドキュメント・記事を参考にさせていただきました。

Compose のネットワーク機能 — Docker-docs-ja 17.06.Beta ドキュメント

qiita.com

qiita.com

qiita.com

o21o21.hatenablog.jp

疎通の方法について

ということで、上記の記事と同じような話にはなりますが、別々のdocker-composeに属するコンテナ同士で疎通させる方法についてです。

それぞれ docker-compose がdefaultで持っているnetworkに加えて、疎通するための新しいdocker networkを作成します。

docker network create common_network

と、自分だけが開発しているものであればこれでいいのですが、開発しているRailsアプリケーションは、docker-composeコマンドを含めた一連の立ち上げコマンドをMakefileでまとめています。
なので、コンテナとRailsサーバーを起動するmakeコマンドの中に、上記のnetwork作成コマンドを入れておきました。

次に、docker-compose.ymlにnetworkまわりの設定を追加します。
今回は両方のdocker-compose.ymlのservice nameが全く同じ構成だったので、aliasを追加しました。

ひとつめのdocker-compose.yml

version: '3'
services:
  db:
    image: mysql:5.7
    ports:
      - "3306"
    environment:
      MYSQL_ROOT_PASSWORD: "hogehoge"
    volumes:
      - db:/var/lib/mysql
  web:
    build:
      context: .
      dockerfile: docker/web/Dockerfile
    command: bundle exec rails server --port=3000 --binding='0.0.0.0'
    volumes:
      - .:/first_web
      - bundle:/usr/local/bundle
      - ./node_modules:/second_web/node_modules:delegated
    ports:
      - "3000"
    depends_on:
      - db
    tty: true
    stdin_open: true
    networks:
      default:
      common_network:
        aliases:
          - first_web
volumes:
  bundle:
  db:
networks:
  common_network:
    external: true

ふたつめのdocker-compose.yml

version: '3'
services:
  db:
    image: mysql:5.7
    ports:
      - "3306"
    environment:
      MYSQL_ROOT_PASSWORD: "hogehoge"
    volumes:
      - db:/var/lib/mysql:delegated
  web:
    build:
      context: .
      dockerfile: docker/web/Dockerfile
    command: bundle exec rails server --port=3000 --binding='0.0.0.0'
    volumes:
      - .:/second_web
      - bundle:/usr/local/bundle
      - ./node_modules:/second_web/node_modules:delegated
    ports:
      - "3000"
    depends_on:
      - db
    tty: true
    stdin_open: true
    networks:
      default:
      common_network:
        aliases:
          - second_web
volumes:
  bundle:
  db:
networks:
  common_network:
    external: true

RailsのAction CableとWebpackerとVue.jsを使ってチャットを作成してみる

もう2ヶ月くらい前になりますが、Action Cableを用いたチャットの実装にチャレンジする機会がありました。
このときには、Railsの中でVue.jsをどう扱うのかについての一例を見ることもできたので、記念(?)にざっくりしたコードを残しておきます。

1. rails newと、webpackerでVueの初期化

rails new したあと、Gemfileに gem "webpacker" を追記し、bundle install した後、以下のコマンドを実行します。

$ bundle exec rails webpacker:install
$ bundle exec rails webpacker:install:vue

2. モデルを作る

$ bundle exec rails db:create
$ bundle exec rails g model message content:text user_id:integer
$ bundle exec rails g model user name:string email:string
$ bundle exec rails db:migrate
class User < ApplicationRecord
  has_many :messages, dependent: :restrict_with_error
end
class Message < ApplicationRecord
  belongs_to :user

  validates :content, presence: true

  after_create_commit { MessageBroadcastJob.perform_later self }
end

3. コントローラの作成

class HomeController < ApplicationController
  def index
    @messages = Message.all
  end
end

4. Actioncableのインストール

$ yarn add actioncable

5. Viewを作る(Vueコンポーネントの実装)

app/javascript/packs/application.js

import Vue from 'vue/dist/vue.esm'
import UserChat from '../components/user-chat.vue'
import ActionCable from 'actioncable';

const cable = ActionCable.createConsumer('ws:localhost:3000/cable');
Vue.prototype.$cable = cable;

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    el: '#main-container',
    data: {},
    components: { UserChat }
  })
})

app/javascript/packs/components/user-chat.vue

<template>
<div>
  <div>
      <div v-for="item in messages" :key="item.message.id">
        <div>
          <div>{{ item.message.content }}</div>
      </div>
    </div>
  </div>
  <div>
    <div>
      <input type="text" v-model="message" placeholder="入力してください ...">
      <span>
        <button type="button" v-if="userMessageChannel" @click="speak">Send</button>
      </span>
    </div>
  </div>
</div>
</template>

<script>
export default {
  data() {
    return {
      message: "",
      messages: [],
      userMessageChannel: null,
    };
  },
  props: ['userId'],
  created() {
    this.userMessageChannel = this.$cable.subscriptions.create( "UserMessageChannel", {
      received: (data) => {
        this.messages.push(data)
        this.message = ''
      },
    })
  },
  methods: {
    speak() {
      this.userMessageChannel.perform('speak', { 
        message: this.message,
        user_id: this.userId,
      });
    },
    // 以下、今回のViewでは使っていませんが、LINEのように自分からのメッセージと他ユーザーからのメッセージでスタイルを分けるときなどに使います
    messageClass (user_id) {
      return {
        "right": user_id === Number(this.userId)
      }
    },
    dataClass (user_id) {
      return {
        "float-right": user_id === Number(this.userId)
      }
    }
  },
};
</script>

app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>VueActioncable</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all' %>
    <%= javascript_pack_tag 'application' %>
  </head>

  <body>
    <div id="main-container">
      <%= yield %>
    </div>
  </body>
</html>

app/views/home/index.html.erb

<% @messages.each do |message| %>
  <div>
    <%= message.content %>
  </div>
<% end %>
<!-- current_userはdevise gemを入れるなどでログイン実装することによって使えます -->
<user-chat user-id="current_user.id"></user-chat>

6. チャンネルを作る

$ bundle exec rails g channel user_message speak
class UserMessageChannel < ApplicationCable::Channel
  def subscribed
    stream_from "user_message_channel"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end
  
  def speak(data)
    Message.create!(
      user_id: data['user_id'],
      content: data['message']
    )
  end
end

7. Jobの作成

$ bundle exec rails g job MessageBroadcast
class MessageBroadcastJob < ApplicationJob
  queue_as :default

  def perform(message)
    ActionCable.server.broadcast "user_message_channel", message: message
  end
end

8. ルーティングを追加する

Rails.application.routes.draw do
  root to: 'home#index'

  mount ActionCable.server => '/cable'
end

以上です。

参考にさせていただいた情報

qiita.com

qiita.com

qiita.com

Railsで、Action Mailerとletter_opener_webを初めて使いました

Action Mailer、すごくベーシックな実装なはずなのに、なんか、今まで縁がなかったんです。
Railsチュートリアルでやったのかな? そのへんも記憶にない...

ということで今回は、ローカル環境でletter_opener_webを使ってメールを確認するところまで、やっていきます。

1. Gemfileletter_opener_webを追加する

group :development do
  gem 'letter_opener_web', '~> 1.0'
end

追加したら、コマンドラインbundle installします。

$ bundle install

メール確認用画面を、config/routes.rb に追加します。

Rails.application.routes.draw do
  root to: "home#index"

  # 省略...

  mount LetterOpenerWeb::Engine, at: '/letter_opener' if Rails.env.development?
end

2. config/environments/development.rb に設定を追加

Rails.application.configure do

  # 省略...

  config.action_mailer.perform_caching = false

  config.action_mailer.default_url_options = { host: 'localhost:3000' }
  config.action_mailer.delivery_method = :letter_opener_web

  # 省略...
  
end

production.rbにはメールの設定なんかを書いたりしますが、今回は割愛。

3. Mailer を作成する

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

$ rails g mailer UserMailer

生成したメーラーを、必要に応じて調整します。

app/mailers/user_mailer.rb

class UserMailer < ActionMailer::Base
  default from: "hoge@gmail.com"

  def send_message_to_user(user)
    @user = user
    mail to: @user.email,
         subject: "メールの件名が入ります"    
  end
end

4. メール本文を作成する

app/views/user_mailer/send_message_to_user.text.erb を作成します。
メソッド名.text.erb という名前になるので注意しましょう。 ファイルの内容は以下のような感じです。

<%= @user.name %> さま

いつもお世話になっております。
株式会社●●です。
この度は、キャンペーンにご応募いただきまして、ありがとうございました。
当選発表は、商品の発送をもってかえさせていただきます。

株式会社●●

5. メール送信処理

メール送信をしたいタイミングで、Mailerのメソッドを実行します。

class EntryController < ApplicationController

  def create
    @entry = Entry.new(entry_params)
    if @entry.save
      # ここでメールを送信する
      UserMailer.send_message_to_user(@entry.user).deliver_now
      redirect_to root_url
    else
      render 'new'
    end
  end
end

6. メールが送られたのか確認する

最初に config/routes.rb に追加した、メール確認用画面を開きます。 http://localhost:3000/letter_opener を開くと、以下のようが画面が開き、送信処理があったメールを一覧できます。(実際に送信されているわけではありません)

f:id:c5meg1012:20180729195634p:plain