READYFOR Tech Blog

READYFOR のエンジニアブログ

Storybookをホスティングしてレビューが爆速になった話

こんにちは、エンジニアリングマネージャーの岡村です。
社員全員テレワークの環境にも慣れてきて、ワークフロー改善と共にREADYFORの開発環境も日々改善しております。

概要

StorybookをNetlifyへホスティングすることで、PR単位でデプロイされるためデザインの確認・レビューがとても楽になったので紹介です。

導入の背景

READYFORのアーキテクチャ上もっとも有効だった

f:id:resqnet:20200612113037p:plain

ざっくりREADYFORのフロントエンドアーキテクチャはReact On RailsとElements(UI Library)で構成されており、デザイン手法にAtomicDesignが採用されています。 Elements(UI Library)はDesignSystemの一部として構成され、ドメインに依存しないコンポーネントはElementsへ開発しています。 そのため、確認をする際にはElementsのコンポーネント・READYFORのコンポーネントをそれぞれに確認する必要があります。

レビューコストがかかっていた

コンポーネントデザインを同じ粒度で確認できるようにStorybookを導入しています、しかし、デザイナー・PMへのレビューを行うための環境作成コストは負荷がありました。

f:id:resqnet:20200612112853p:plain PRをレビューブランチに反映or画面共有で確認してもらう必要があった。

弊社ではスクラム開発を採用しているため、スプリントレビュー時に都度この工数が発生していた。 また、開発中に確認をしてもらうのにその場で画面を見せたり(今だとハングアウト・Zoomなど)していました。

Storybookをホスティングし解決

この問題を解決するためにNetlifyのPR Previewを利用しました。
これによりPR毎にStorybookをbuildすることでPR単位のレビューが安易になりました。

f:id:resqnet:20200612112905p:plain デザイナーはURLを共有することでいつでも確認が可能です。

URLはGitHubのPRにリンクが貼られるためデザイナーからのレビューもPR上で行いやすくなります。

現場デザイナー・PMインタビュー

実際に現場のデザイナー・PMへStorybookについて聞いてみました

  • PM(江藤さん)

    個人的には「レビューが手軽にできるようになった」がメリットだと感じています! もしStorybookがないとすると... テスト環境に上げる工数がかかる テスト環境の数自体が限られているので、同時に複数Issueを進める場合に利用環境の調整コストもかかる ので、この2つのコストが抑えられているのがデカイと思います。
    上記2つのコストが抑えられた結果として... 「とりあえず動くものを作ってPMに見せちゃおう」となり、 PM-ENG間のコミュニケーション量が増えて、 認識の齟齬が早期に解消できるようになったと思います!

  • デザイナー(今野さん)

    Figmaのコンポーネントと名称を統一しているため、コミュニケーションがしやすいです。 またボタンのHover, Activeなどトランジションを確認しやすく、 検索機能や、リストの階層化などあってFigmaより探しやすいです。 拡大機能や、背景色を変更できるので、実装後の気づきを発見しやすくなります!

エンジニア同様、デザイナー・PMさんもエンジニア同様確認するコストが減った印象があるようです。
確認・ブラッシュアップの工数はすごく重要だと思います。 このイテレーションが早くなるのは効果的だと思えます。

まとめ

「Storybookの導入が運用コストに見合わない」という課題は一定あるかと思います。

しかし、テレワークが推奨される今、Storybookをホスティングすることで得られる恩恵は非常に大きいと感じました。

参考になれば嬉しいです。

募集

READYFORでは現在「React・TypeScriptの開発ができるフロントエンドエンジニア・リードエンジニア募集しています!!」

  • DesignSystemの整備・構築
  • モノリスなアーキテクチャからの分離
  • 新規SPA構築
  • 大規模リファクタ

など、ぐいぐい進められるエンジニア募集しています!! https://www.wantedly.com/companies/readyfor2/projects

READYFOR Tech Blogのヘッダーをリデザインしました

こんにちは、READYFORに2020年2月から1人目のプロダクトデザイナーとして入社した今野(@kyota)といいます。 今日はこのテックブログのヘッダーのデザインを変更したお話をさせていただきます。

なぜ変更したか

僕が入社した2020年2月3日にちょうどこのテックブログは立ち上がり、「みんなでテックブログ書くぞー!!」と社内で盛り上がっておりました。

ただ、ブログの見た目が社内にあった写真素材をそのまま使っており、正直なところちょっと残念な見た目になっていました。

f:id:rfkonno:20200604175612p:plain:w480
↑変更前のブログのデザイン

そこで、READYFORらしさもありつつ、READYFORのエンジニアの色がでるような形でデザインを検討をすることにしました。

どのようなプロセスでデザインしたか

READYFORに入社したばかりだったこともあり、会社の社風を感じとりつつ「READYFORとは、、、」「READYFORとは、、、」と頭の中で連呼しながら、特徴や性格をインプットするところから始めました。

今回に限った話ではありませんが、今後 READYFORのプロダクトを作っていくにあたっても必要な考えなので、目にしたこと、聞いたこと、感じたことなど、日々 メモをしております。

インプット後、以下4つの方向性でデザイン案を作成し、社内関係者にプレゼンをしました。

f:id:rfkonno:20200604181803p:plain

A案

READYFORロゴに使われている有機体を使った案。 一番READYFORらしさが伝わる案です。 ただ、デメリットとして、READYFORのサービストップページや、コーポレートサイトでもすでにこちらの有機体を使っているため、全体的に似てしまうという懸念があります。

B案

READYFORでは、「エンジニアの乳化」という考えがあります。 こちらの意味は、以下CTOの記事を引用させていただきます。

卵を入れると水と油が混ざり合ってマヨネーズが作れるようになる、あの「乳化(にゅうか)」です。 私たちが「テックカンパニー化」というとき、それは「エンジニア/非エンジニア」と職種で線引きして単純にエンジニアの数を増やすことでは決してなく、エンジニアリングが組織全体に広がっている状態になることです。
クラウドファンディングのプラットフォームとして様々な種類のお金の流れを扱う READYFOR では、プロジェクト審査や支援金の会計処理など、多くの業務オペレーションがシステムと密接に繋がっています。それを支えるためにはエンジニアが各組織部門に乳化していくことがとても重要で、それによってオペレーションの卓越性が高まっています。

引用元:READYFOR の「テックブログ開設」までの軌跡 - READYFOR Tech Blog

この「乳化」というキーワードを元に、混ざり合い溶け込むイメージで作成したのがこちらのB案です。

C案

B案ベースに力強くロック調のフォントで作成したものがこちらのC案です。 READYFORでは、音楽好きが多く、きちんと主張してアウトプットできるロックなエンジニアが多いなーと個人的に感じたため、こちらのアイディアが生まれました。

D案

READYFORらしさから、かけ離れた案です。 「READYFOR Tech Blog」の頭文字をブロックっぽい形にし、可愛らしさと、モノづくりしているイメージを出しました。
(正直、こちらは他と比較しやすくするための捨て案かなーと思って作ったのですが、なかなか好評でした)

案を絞る

A案は、READYFORサービスと似てしまい、テックブログの独自性が無くなるため削ることに。

B案とC案は方向性が同じだったため、エンジニアの特徴が出ているC案を残しました。

D案は好評だっため、最終的にC案とD案で、エンジニアの社内投票で決めることにしました。

投票の結果...!!

11人のエンジニアの方に投票していただき、C案(下図では①)で決まりました!

f:id:rfkonno:20200611180246p:plain
自分のスタンプが含まれているため11人の投票となっています

ブラッシュアップ

案を作成した段階では、細かな調整は省いていたため、案が決定した後にブラッシュアップしていきます。 色味や、背景画像の微調整を重ねたり、ロゴタイプのカーニングの調整などしました。

f:id:rfkonno:20200612090612p:plain:w320
気になった箇所を微調整していく

リリース🎉

その後、ブログにデザインを実装し、4月にリリースをしました。

f:id:rfkonno:20200612092228p:plain

f:id:rfkonno:20200612112416p:plain

最後に

本当はヘッダー以外にブログ全体のデザインを調整したかったのですが、結構な工数がかかり断念したため、また別な機会にできればなーと思っています。

今回のデザイン変更を機に、よりREADYFORのことを知って興味を持っていただけれたら幸いです!

READYFORテックブログはまだまだ始まったばかりで、これからもどんどん発信と成長していきますのでお楽しみに!

オンラインもくもく会レポート

こんにちは、エンジニアリングマネージャーの岡村です。

4月24日、オンラインもくもく会を開催しました。

コロナウィルスの影響で弊社もテレワークへ移行し、コミュニケーションもオンライン勉強会やオンライン飲み会といった形に移行していく中でもくもく会もオンラインで行いました。そのレポートをお届けします。

f:id:resqnet:20200529103702p:plain

当日の流れ

18:00 集合、各自取り組むテーマの発表
18:10 もくもく
19:40 進捗報告
20:00 解散

進捗報告

初めてのオンラインもくもく会ということで、 特にテーマを絞らず社内メンバーで開催となりました。 当日のハイライトとコメントを紹介します。

  • Toggleコンポーネントを作る f:id:resqnet:20200521101414p:plain

    考える時間よりも作業に没頭したい気分だったので、もともと業務で作る予定だったToggleスイッチを作成しました。 デザインを見ながらマークアップ+スタイリングしていくのは、デザイナーのこだわりを改めて垣間見れたりするので楽しいですね!

  • TwitterShareコメントをいい感じにする f:id:resqnet:20200521101041p:plain

支援したことをTwitterでシェアしたユーザーが、「自分が何番目に支援したか」を追記して投稿しているのを結構見かけた。わざわざ追記しなくても済むよう、defaultで記載してあげたらシェアして応援する気持ちも増えるかなと思って取り組んでみた。

  • Elmチュートリアルに触れる
    f:id:resqnet:20200521101119p:plain

Elmの持つ実行時エラーの存在しない世界観や高品質な設計パターンを肌で感じてみたいと思い、まずはElmチュートリアルでElmを完全に理解してみました。 早くElmなんも分からん領域に達してみたいです。

その他以下のような進捗報告がありました

  • SPAページ向けCI/CDを構築する
  • 自然言語100本ノック
  • SystemSpecを書く
  • Sorbetを試してみる
  • Webアクセシビリティ対応についてまとめる
  • 料理してみた

よかったこと / 気になったこと

よかったこと

  • シェアが画面共有でささっとできる
  • 自宅なのでリラックスできる
  • オンライン x テーマフリーだとかなり自由にもくもくできる(料理・筋トレ)

気になったこと

  • 周りの空気を感じづらい
  • 家族のご飯時間と重なりバタバタした
  • 雑談もしたいが生活音がマイクに大きく入ると気になる

最後に

テーマを絞っていないため、それぞれ興味があることや、やろうと思っていたことなどに取り組み、発表時には「おー!」や「すごい!」などの声が多い会となり知らない技術に触れられる良い機会となりました。社内メンバーで開催された会ということもありネタを仕込んで来る人も。

オフラインの良さは同じ空間を共有できることに大きなメリットがあると思いますが、それぞれの自宅環境を活かし選択と集中がしやすいオンライン環境ならではの良さもあるなと感じました。

今後もオンライン・オフラインに関わらず定期的にもくもく会開催をしていきたいと思います。

READYFORエンジニアとしてJoinしました!~アクセシビリティを添えて~

はじめまして。4月からフロントエンドエンジニアとしてJoinした大房 稜と申します。 twitterではrandy_39という名義でやっています。

入社して約1ヶ月が立ちましてREADYFORで働いている皆さまは本当に素晴らしい方たちばかりでとても刺激のある毎日を過ごしております! 私がこの1ヶ月で感じたREADYFORの良さと、ブログタイトルにもあるアクセシビリティという個人的な好きな話題を書ければと思います。

READYFORに参画した理由

私の前職はWeb制作会社で働いていました。元々未経験で採用されフロントエンドエンジニアとして勉強していた日々でした。 特に不満も無く働かせてもらっていたので転職したいという強い意志はなく、スカウトメールなどもスルーをしていたのですが、READYFORからのスカウトメールでの概要で誰もがやりたいことを実現できる世の中をつくるというビジョンにとても共感しました。

また現CTO町野さんのnoteの記事 を見て組織作りから同じ想いをもった人々と働けたら絶対に楽しいだろうな、とカジュアル面談でまず話を聞きました。

いきなりフルリモート

私が入社する前の2月頃からREADYFORではコロナの影響を考えリモート推奨ということでしたので、入社日はPC端末を受け取りに行きその翌日から現在までフルリモート環境の中で働いています。 コロナ感染拡大の真っ最中に通勤電車には乗りたくありませんでしたのでほぼ初日からリモートの対応はありがたかったのですが、いきなりリモートで働くのは流石に初めてでしたので不安の中業務をスタートしました。

業務スタートしてみればドキュメントには情報が整備されてあり、MTGの際にはビデオ通話やコードに関してはVSCodeのLive Share機能での共有、エンジニア同士では毎週のオンラインランチや月1のもくもく会、またまたNintendo Switchを持っている有志の人達でのゲーム大会、部署を跨いだオンラインシャッフルランチなど業務以外のところでもすぐ馴染めるような取り組みがなされていたのでとても助かりました。雑談用のenjoyチャンネルが多数あるのが素晴らしいですね!

google meetのオンラインもくもく会画面のスクリーンショット Webアクセシビリティについて話している大房
エンジニアもくもく会の様子

READYFOR社員の行動指針の中に#隙手間かけるというものがあるのですが、わからないものは誰でも即レスポンスをくれてコミュニケーションが難しいということはありませんでした。感謝。

アクセシビリティとは

話題を変えて個人的な話としてアクセシビリティについて書きたいと思います。 アクセシビリティという言葉を聞いたことがない人に説明を書きますと、

  • Access(アクセス)+ -bility(可能性)

  • アクセスのしやすさ

  • 利用のしやすさ

というシンプルに言えば誰でもサービスなどにアクセス出来て使えることというものです。

アクセシビリティという言葉を少し知っている方で言えば障害者の方向けの対応を実装なりする、と考えている方が多いと思います。

よくある地方自治体サイトでの文字サイズ縮小・拡大の機能・音声読み上げ機能・色を何パターンか切り替えるような機能など見たことがあるかもしれません。 これらの機能の実装などは実はアクセシビリティ的にいらない三種の神器という観点があります。参考

Webというものは誰でもアクセス出来ることが本質なので、特別障害者の方に向けた機能の実装をするということではなく使っているユーザー全てを対象とすることがWebアクセシビリティと思っています。

怪我をしてしまって一時的に右手が動かしずらい方、日本人男性20人に1人いると言われる「色覚多様性者」の方、などのユーザーの方でもサービスを使えることがアクセシビリティということなんですね。視覚障害者の方でなくても音声読み上げを使ってサイトを閲覧しているユーザーもいるかも知れません。(自分の話です)

知らず知らずにアクセシビリティの恩恵を受けているパターンもよく見かけます。

  • iPhoneのアクセシビリティ設定の視差効果を減らすをONにしたらバッテリー持ちが良くなる情報

  • ゲームでのアクセシビリティ設定のある項目をONにしたらやりやすくなるからオススメ的な情報

健常なユーザーであってもこのようにサービスの体験を広く底上げ出来ることが良いですね!

READYFORとアクセシビリティ

このようにアクセシビリティというのは誰でもアクセスできて使えるものというところでREADYFORのビジョンの話に戻るわけですが、誰もがやりたいことを実現できる世の中をつくるということはまず誰でも使えるサービスを作ることも必要で、自分が何か貢献出来てREADYFORで働き誰かの夢を応援できる未来を想像してとてもわくわくしました。

直近で言えばコロナ基金のプロジェクトが多数のメディアに紹介され、たくさんの支援者が集まり、READYFOR史上最大の支援額ということでもの凄くサービスが改善・成長をしているのを間近で体感しています。

これから

とはいえREADYFORのサービスはアクセシビリティ、ユーザビリティ的、それ以外にもまだまだ課題がたくさんあります。 自分の役割としてはこういった改善をして使いやすくなったよ!というのをまた記事としてアウトプットしていきたいと思います。

最後に、READYFORでは共に戦ってくれる仲間を求めています。

共に想いが乗ったお金の流れを支えるサービスを作りませんか?

https://www.wantedly.com/companies/readyfor2/projects

東大松尾研の「GCIデータサイエンティスト育成講座」を修了しました

はじめに

はじめまして。浦野昌平 ( @s_runoa ) です。 READYFOR株式会社でエンジニアとして働いています。 コロナの影響で授与式兼交流会が延期になったため修了証はまだありませんが、先月末に東大の松尾研が主催しているGCIデータサイエンティスト育成講座を修了しました。 今回はその参加レポートを書いていきます。

講座について

READYFOR最初期の投資家でもある東大の松尾先生が主催の講座です。 今回は駒場キャンパスとオンラインで同時開催された社会人も参加できる講座に参加しました。

gci.t.u-tokyo.ac.jp

カリキュラム

カリキュラムはこのように組まれていました。 1週間に1,2章ずつ学習し、各章に演習課題や宿題があります。 講座ではすべての宿題をクリアすることが修了条件の一つになっており、1日1,2時間程度の勉強時間を確保して進めました。

1. 本講座の概要とPythonの基礎
2. 科学計算、データ加工、グラフ描画ライブラリの使い方の基礎
3. Pythonによる科学計算(NumpyとScipy)
4. Pandasを使ったデータ加工処理
5. Matplotlibを使ったデータ可視化
6. 統計・確率
7. 機械学習の基礎(教師あり学習)
8. 機械学習の基礎(教師なし学習)
9. モデルの検証方法とチューニング方法
10. データサイエンティスト中級者への道

また後半にはコンペや総合課題がありました。 コンペではKaggleを模した形式になっており、実際のデータを分析して他の生徒とスコアを競います。 でもSlackでお互いの気付きや悩みを共有し合ったり、定期的に公開されるお互いのスコアをみて自分のアルゴリズムに足りないところを考えるなど、ただ競うだけに留まらない学びがありました。

本家Kaggleにもそのような議論し合う場があり、有益な情報にはポイントが入る仕組みになっているそうです。 ひたすら自分が一番を目指すのではなく、参加者全員がデータへの理解を深めつつスキルアップしていける優れた仕組みだと感じました。 元々、プログラマー界隈には学びを共有しつつお互いに成長していく文化がありますが、賞金のかかったコンペでもそれを再現できるのは業界の強みですね。

学習環境

学習環境にはハンズオン型AI人材育成サービスであるiLectを使いました。 Jupiter Notebook同様に教科書とプログラムエディタとプログラムの実行環境が一体化した構成になっており、教科書を読んでその場で実行できます。 オンラインのプログラミング学習サービスも教科書を見ながら学習できるように工夫されていますが、より強い一体感がありました。 とてもハードル低く自然と学習できるためプログラミング未経験の人にもお勧めです。

www.ilect.net

質問はオンラインでSlackを通じて行います。 基本的には教材が配られて自習する形式ですが、スクールのメンターと生徒が入ったチャンネルで生徒たちが自由に質問したり意見交換したりしていました。

また様々な分野の専門家を招いたオンラインの講座、自由参加のもくもく会も開催されていましたし、修了後は松尾先生による講義も予定されているので楽しみです。

f:id:srunoa:20200421204403p:plain
iLect

こんな人におすすめ

プログラミング経験に関わらず、機械学習に興味のあるなら誰でもお勧めできる講座です。 機械学習を早く身につける意味ではプログラミング経験があるに越したことはありませんが、身につけた技術を生かそうとするとビジネス的な考え方が必ず必要になります。 なのでビジネス的な考え方を身につけた人がこの講座で技術を手に入れることでより深く仕事に生かせるのではないかと思いました。

実際にやってみるには

今は受講生の募集は特にしていないようです。

gci.t.u-tokyo.ac.jp

でも実はこの講座で使っている教材はこちらのページで無料公開されてるため、誰でも勉強することができます。 (演習課題とコンペを除く)
※ただしこちらの教材はダウンロードページに書かれている通り、個人で学習する目的のみで利用可能となっているのでご注意ください。講習会・教室での利用や企業内での講習など、商用での利用は認められていません。

weblab.t.u-tokyo.ac.jp

iLectを使うことはできませんが、例えばGoogleが無料で公開しているJupyterノートブック環境であるColaboratoryで同様に動かすことができます。

colab.research.google.com

準備

まず上記ダウンロードサイトからZipファイルをダウンロードして.ipynbファイルを確認しましょう。 これがJupyter Notebookで使うファイル形式です。 このファイルをGoogle DocsにアップロードするとColaboratoryで開くことができます。

f:id:srunoa:20200421204718p:plain
Colaborator

簡単な使い方

開くとこのような画面が出てきます。 上で書いたようにColaboratoryではコードとテキストが一体化しています。 この画像の赤枠がコードセル、青枠がテキストセルです。 テキスト部分が教科書、コード部分が実践です。 コードの隣の▶を押すことで実行し、すぐ下にその結果が出てきます。

テキスト部分を読んで理論を学び、コード部分を実行して動きを確認するという流れで効率的に勉強できるので、興味があれば試してみてください。

実際にデータを分析するときにもこのエディタを使い、データ読込用のセル、データの特徴抽出用のセル、学習用のセルのように整理して使います。 普段プログラミングをするときもコード内に適宜コメントを挟みますが、このエディタを使うと学習の仕組みをより丁寧に説明することができます。

f:id:srunoa:20200421204744p:plain
Colaborator

今後

今回、この講座を通じて機械学習に必要な考え方や基礎的な技術を学ぶことができました。 これからは私も会社のデータを機械学習を使って分析したり、Kaggleに挑戦したりして社会に貢献していきたいです。

コロナが流行る中でアメリカホワイトハウスがKaggleで賞金ありの分析コンペを公開するなど、世界中で分析の需要は高まっています。 一部SNSでは "医療の素人であるデータサイエンティストが未曾有の危機に対して口出しするな" という意見も見られました。 でも個人的には、一人の専門家では処理できないほど多くのデータを元に分析するからこそ、見えてくるものもあるのではないかと期待しています。

最後に、このような講座を無償で提供し、教材の作成や運営をして頂いた関係者の皆さんに感謝いたします。 ありがとうございました。

READYFORにおけるSlackのチャンネル活用方法を紹介します!

こんにちは、コーポレートエンジニアの佐々木です。

READYFORでは、社内コミュニケーションツールとして「Slack」を採用しています。
Slackのチャンネル運用についても活用の方法を社内に発信しており、その一部をご紹介します。

パブリックチャンネルでのオープンなコミュニケーション

Slackでのコミュニケーションは、基本的にパブリックチャンネルでのやりとりを推奨しており、チャンネル数も400件以上あります。
パブリックチャンネルの参加は自由で、退出も自由です。チャンネルの作成は自由ですが、運用が変わった時点で見直しを行い、使わなくなったチャンネルはアーカイブすることを促しています。
また、使われなくなったチャンネルについても、3ヶ月投稿がないチャンネルはアーカイブされるようにしています。

チャンネルアーカイブ
チャンネルアーカイブがされます

READYFORでは、Slackのチャンネルを大きく4つに分類しています。

  • 全社チャンネル

  • 部門・チームチャンネル

  • 組織横断チャンネル

  • システム通知チャンネル

全社チャンネルはメンションの使い方に注意

全メンバーがチャンネルに入っていることを前提とした通知・コミュニケーションが行われるチャンネルです。このチャンネルは、社内の全員へ通知がされるということから、チャンネル数を少なくし、発信の方法にも注意を払っています。

  • #all-announcement は、人事・評価制度の改定、経費精算方法の変更など、全メンバーにインプットがなされないと業務影響を及ぼす可能性がある情報が投稿されます

  • #all-general は、サービス・プロダクトのアップデート情報や朝会の議事録など、全メンバーが把握することを推奨する情報が投稿されます

チャンネルへの投稿は、即時性を求めない場合メンションは付けない方が、落ち着いて読まれる可能性が高くなります。 @here@channel など、たくさんメンションがされると、通知に反応してメッセージを開き、中身がしっかり読まれないケースが増えます。その結果、お願いしたいことが実行されなくなってしまうことに繋がります。また、他の重要な情報が流れないよう、簡潔に要旨を絞った投稿とすることも大切です。

全社チャンネルでのメンションの使い方
全社チャンネルでのメンションの使い方

部門・チームチャンネルは情報を受け取るべきメンバーごとに

部門やチームのメンバー内でコミュニケーションが行われるチャンネルです。それぞれ共通の略称を細かく決めて、接頭辞につけてチャンネルを作成しています。
部門・チームのチャンネルは、レスポンスしやすいよう、所属部門の細かなユニットなど情報を受け取るべきメンバーごとでのチャンネル作成を推奨しています。また、同じメンバーでのやりとりは同じチャンネルとして、出来るだけコンテキストごとに細かくチャンネルを分けない方が、チャンネルの切り替えも少なく、コミュニケーションがとりやすくなります。

  • READYFORで使われている部門略称例
略称 部門
dev 開発
pr 広報
legal 法務・コンプライアンス
  • チームチャンネルの様子
    エンジニアリンング部門バックエンドチームのチャンネル
    エンジニアリンング部門バックエンドチームのチャンネル

業務外のコミュニケーションも組織横断チャンネルで

組織横断チャンネルは、他部門への要望・依頼等 、組織を横断するコミュニケーションを行うチャンネルです。
Slackでは、チャンネルをアルファベット順に並べることができるため、他部門へのリクエストを行うチャンネルの接頭辞を #req- に統一して、明確にチーム内のコミュニケーションと分けることで、投稿するチャンネルを迷いにくくしています。
また、社内イベントなど、部門やチームを超えて有志のメンバーが集まってコミュニケーションをとりたい時にもチャンネルを活用しています。

表記方法 用途 チャンネル例
req-[〇〇] 他部門への作業依頼・要望等を行う req-corpsys
pj-[〇〇] 部門・チームには紐づかない一時的な社内の人の集まり pj-忘年会2019
grp-[〇〇] 部門・チームには紐づかない恒久的な社内の人の集まり #grp-onboarding

リクエストチャンネル
コーポレートシステム部へのリクエストチャンネル

また、業務外の雑談的なコミュニケーションもとても活発です。 #enjoy-[〇〇] チャンネルには、趣味や共通の話題、学びを深めたい分野ごとにチャンネルがあります。
#times-[name] チャンネルでは、個人が自由に想ったことを発信しています。そこでの話題が派生して、業務に繋がることもあります。

表記方法 用途 備考
times- 個人のやっていること(分報、日報)、気づきなど
enjoy- 楽しいチャンネル・業務以外の話をしたいとき
学ぶ系はenjoy-study-XX

楽しいチャンネルもあります

システム通知チャンネルは、用途や情報の優先度に応じて

Slack以外のツールやサービスと連携して、システム通知を行うチャンネルです。チームごとに、用途や情報の優先度に応じて、通知されるチャンネルを分けるなどしています。また、全社で利用しているツールとも連携していて、業務の中で発生する通知に気付きやすいようにしています。

  • 全社員任意のシステム通知は、 #[システム名]

  • 部門固有のシステム通知は、 #<部門略称>-[システム名]

システム通知チャンネルの一部を並べてみる

これまでは?

以前は、LINE、Facebook、メール、Slack等で社内コミュニケーションを取っていたため、情報が混在していました。2019年4月ごろに、社内コミュニケーションツールをSlackに一本化し、チャンネル名の命名規則をつくるなどして運用を開始しました。
その後、組織拡大に伴い、やりとりされる情報量も社内で扱われる情報の種類も増えてきたことから、チャンネル数も指数関数的に増加傾向にありました。そんな中、Slackでのコミュニケーションに対して、社内でいくつか問題が起り始めました。

社内で起きていた問題

そこで、改めて個々人が「必要な情報が優先してインプットされる状態」となり、その上で「必要なときには欲しい情報が取りにいける状態」を目指し、Slackのチャンネル活用の方法を見直しました。

まとめ

READYFORではこのようなチャンネル整理で、Slackを活用しています!
日常的なコミュニケーションは、組織のフェーズや文化によっても常に変化していきますが、ストレスなく円滑なコミュニケーションが行えるよう、情報を受け取る側も、情報を発信する側も、お互いに配慮しあえるルールがあるといいですね。

Terraform のテストを Golang で書く!

こんにちは。READYFOR 株式会社で SRE として働いている ジェダイ・パンくず🚀 と申します。

突然ですが、皆さんの現場ではインフラのテストの仕組みは導入済みですか?我々はまだ出来ていません(笑)。

READYFOR では IaaS として AWS を、IaC として Terraform を導入しているのですがコードのテスト・コードによってデプロイされた状態のテストを何かしらの仕組みを使って実践したいなぁと考え、今調査している最中です。

今回は Terraform のテストを書くツール Terratest について調べた内容を皆さんに共有したいと思っています。また AWS の状態をテストする仕組みとしてよく知られている Awspec との比較も行っていきたいと思っています。

必要になるモノ

事前に必要になるソフトウェアの一覧です。

  • Golang (requires version >= 1.13)
  • Ruby (required by Awspec)
  • Awspec

今回ターゲットにする AWS インフラと Terraform コード

任意の VPC, サブネット上に ECS クラスタ・サービス・タスクを作る Terraform コードを前提にテストを実施していきたいと思います。VPC やサブネットは事前に作成したモノを利用 (terraform の data や variable を用いる) します。

今回 AWS インフラをデプロイするために用意した main.tf と output.tf です。(ID などはマスクさせて頂きました) Terratest のテストを行う際に事前に AWS インフラがデプロイされている必要は無いためここでは terraform apply しません。

main.tf

terraform {
  required_version = ">= 0.12"
}

# ------------------------------------------------
# variables の設定
# ------------------------------------------------
variable "vpc_id" {
  default = "****"
}

variable "cluster_name" {
  description = "example"
  type        = string
  default     = "example"
}

variable "service_name" {
  description = "example"
  type        = string
  default     = "example"
}

# ------------------------------------------------
# 既存 Resource の指定
# ------------------------------------------------
data "aws_vpc" "example" {
  id = var.vpc_id
}

data "aws_subnet_ids" "all" {
  vpc_id = data.aws_vpc.example.id

  filter {
    name   = "tag:Name"
    values = ["rf-sandbox-***-private0-sb", " rf-sandbox-***--private0-sb"]
  }
}

# ------------------------------------------------
# 新規 Resource の作成
# ------------------------------------------------
resource "aws_ecs_cluster" "example" {
  name = var.cluster_name
}

resource "aws_ecs_service" "example" {
  name            = var.service_name
  cluster         = aws_ecs_cluster.example.arn
  task_definition = aws_ecs_task_definition.example.arn
  desired_count   = 0
  launch_type     = "FARGATE"

  network_configuration {
    subnets = data.aws_subnet_ids.all.ids
  }
}

resource "aws_ecs_task_definition" "example" {
  family                   = "terratest"
  network_mode             = "awsvpc"
  cpu                      = 256
  memory                   = 512
  requires_compatibilities = ["FARGATE"]
  execution_role_arn       = aws_iam_role.execution.arn
  container_definitions    = <<-JSON
    [
      {
        "image": "terraterst-example",
        "name": "terratest",
        "networkMode": "awsvpc"
      }
    ]
JSON
}

resource "aws_iam_role" "execution" {
  name               = "${var.cluster_name}-ecs-execution"
  assume_role_policy = data.aws_iam_policy_document.assume-execution.json
}

resource "aws_iam_role_policy_attachment" "execution" {
  role       = aws_iam_role.execution.id
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

data "aws_iam_policy_document" "assume-execution" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["ecs-tasks.amazonaws.com"]
    }
  }
}

output.tf

output "task_definition" {
  value = aws_ecs_task_definition.example.arn
}

Terratest のテストを書いてみる

テストを書く

次に Terratest のテストを書いていきます。

package test

import (
    "fmt"
    "testing"

    "github.com/gruntwork-io/terratest/modules/aws"
    "github.com/gruntwork-io/terratest/modules/terraform"

    awsSDK "github.com/aws/aws-sdk-go/aws"
    "github.com/stretchr/testify/assert"
)

func TestTerraformAwsEcs(t *testing.T) {
    t.Parallel()

    expectedClusterName := fmt.Sprintf("example")
    expectedServiceName := fmt.Sprintf("example")

    // テストで起動するリージョンを複数指定し、どのリージョンでも起動することを確認する
    // awsRegion := aws.GetRandomStableRegion(t, []string{"us-east-1", "ap-northeast-1"}, nil)
    awsRegion := "ap-northeast-1"

    terraformOptions := &terraform.Options{
        TerraformDir: "../",

        Vars: map[string]interface{}{
            "cluster_name": expectedClusterName,
            "service_name": expectedServiceName,
        },

        EnvVars: map[string]string{
            "AWS_DEFAULT_REGION": awsRegion,
        },
    }

    defer terraform.Destroy(t, terraformOptions)

    if _, err := terraform.InitE(t, terraformOptions); err != nil {
        fmt.Printf("Terraform Init Error.")
    }

    if _, err := terraform.ApplyE(t, terraformOptions); err != nil {
        fmt.Printf("Terraform Apply Error.")
    }

    taskDefinition := terraform.Output(t, terraformOptions, "task_definition")

    // 各テスト (次項 "各テストの説明" を参照のこと)

    // (1) クラスタ周りのテスト
    // Reference: https://docs.aws.amazon.com/ja_jp/sdk-for-go/v1/api/service.ecs.Cluster.html
    cluster := aws.GetEcsCluster(t, awsRegion, expectedClusterName)
    assert.Equal(t, int64(1), awsSDK.Int64Value(cluster.ActiveServicesCount))
    assert.Equal(t, expectedClusterName, awsSDK.StringValue(cluster.ClusterName))
    assert.Equal(t, int64(0), awsSDK.Int64Value(cluster.PendingTasksCount))

    // (2) ECS サービス周りのテスト
    // Reference: https://docs.aws.amazon.com/ja_jp/sdk-for-go/v1/api/service.ecs.Service.html
    service := aws.GetEcsService(t, awsRegion, expectedClusterName, expectedServiceName)
    assert.Equal(t, int64(0), awsSDK.Int64Value(service.DesiredCount))
    assert.Equal(t, "FARGATE", awsSDK.StringValue(service.LaunchType))
    assert.Equal(t, expectedServiceName, awsSDK.StringValue(service.ServiceName))
    assert.Equal(t, "LATEST", awsSDK.StringValue(service.PlatformVersion))

    // (3) ECS Task 周りのテスト
    // Reference: https://docs.aws.amazon.com/ja_jp/sdk-for-go/v1/api/service.ecs.TaskDefinition.html
    task := aws.GetEcsTaskDefinition(t, awsRegion, taskDefinition)
    assert.Equal(t, "256", awsSDK.StringValue(task.Cpu))
    assert.Equal(t, "512", awsSDK.StringValue(task.Memory))
    assert.Equal(t, "awsvpc", awsSDK.StringValue(task.NetworkMode))
}

コードの説明をしていきます。

  • import 行で 'terratest' と 'testify/assert' をロードしています
  • expectedClusterName, expectedServiceName で期待するクラスタ名・サービス名を記しています
  • awsRegion でテストの際に AWS インフラをデプロイするリージョンを指定しています
  • defer でテストが終わった後の処理として Destroy することを明記しています
  • ECS クラスタ・サービス・タスク毎にテストが記されています (次項)

各テストの説明

assert 文で Terraform によってデプロイされた AWS インフラの状態でテストしています。ここではそれぞれのテストの意味を説明していきます。

(1) ECS クラスタ

テストされるモノ 期待値
アクティブな ECS サービス数 1
ECS クラスタ名 expectedClusterName
ペンディングタスク数 0

(2) ECS サービス

テストされるモノ 期待値
ECS DesiredCount 0
ECS ローンチタイプ 'FARGATE'
ECS サービス名 expectedServiceName

(3) ECS タスク

テストされるモノ 期待値
タスク定義で記されている CPU ユニット数 256
タスク定義で記されているメモリ量 512
タスク定義で記されているネットワークモード 'awsvpc'

テストの記述方法

テストの1行をピックアップしてテストの書き方について説明します。

assert.Equal(t, int64(1), awsSDK.Int64Value(cluster.ActiveServicesCount))

整数値: 1 と awsSDK.Int64Value(cluster.ActiveServicesCount) が同一であることをテストしている行ですが、cluster.ActiveServicesCount はどの様に知れば良いでしょう?答えとしては 'aws-sdk-go' のドキュメント (下記: クラスタ・サービス・タスク) を確認しつつテストを書いていく作業が必要になります。(この時にエディタの補完機能を使っていると容易に導き出せます)

テストの実行

上記で書いたテストを test ディレクトリに配置します。ディレクトリ構造は下記のようになります。

.
├── main.tf
├── output.tf
└── test
    └── terraform-aws-ecs_test.go

では go コマンドを使ってテストを実行します。

cd test
go mod init test
go test

結果、全てのテストが終了すると結果の末尾に下記のようなログが出力されます。この時に terraform apply, テスト実行, terraform destroy が処理されるので、テスト完了までしばらく待つ必要があります。

PASS
ok      test    80.068s

失敗するケースとして誤ったテストを書きテストを実行すると下記のようなログが得られます。

--- FAIL: TestTerraformAwsEcs (91.04s)
    terraform-aws-ecs_test.go:60:
                Error Trace:    terraform-aws-ecs_test.go:60
                Error:          Not equal:
                                expected: "511"
                                actual  : "512"

                                Diff:
                                --- Expected
                                +++ Actual
                                @@ -1 +1 @@
                                -511
                                +512
                Test:           TestTerraformAwsEcs
FAIL
exit status 1
FAIL    test    91.344s

上記の場合、ECS タスクに定義されたメモリ量が期待したものと異なっていたとエラー出力されています。

Awspec のテストを書いてみる

Awspec は国内のエンジニアの方が開発した AWS 状態をテストするツールです。海外の技術ブログやコードの中にも最近は登場するようになりました。今回 AWS インフラをデプロイするために用いた Terraform のコードに沿って Awspec テストを書いてみました。

require 'spec_helper'

describe ecs_cluster('example') do
  it { should exist }
  it { should be_active }
end

describe ecs_service('example'), cluster: 'example' do
  it { should exist }
  it { should be_active }
  its(:cluster) { should eq 'example' }
  its(:service_name) { should eq 'example' }
  its(:service_arn) { should eq 'arn:aws:ecs:ap-northeast-1:********:service/example' }
  its(:cluster_arn) { should eq 'arn:aws:ecs:ap-northeast-1:********:cluster/example' }
  its(:desired_count) { should eq 0 }
  its(:pending_count) { should eq 0 }
  its(:running_count) { should eq 0 }
end

describe ecs_task_definition('terratest') do
  it { should exist }
  it { should be_active }
  its(:family) { should eq 'terratest' }
end

※ awspec の Resource Type 'ecs_service' のドキュメントによると上記のような記述は書けませんが、, cluster: 'exmaple' を追記してテストを実施することが実際には出来ました。今回も main.tf でデフォルトではないクラスタを作成しているので上記のように記述しています。尚、awspec のドキュメントに対して下記の通り PR をしておきました。

github.com

Terratest, Awspec のテストを比較・考察

両者ともに Terraform のデプロイを行った結果としての AWS インフラの状態をテストしているツールだということがわかりました。Awspec に関しては Resource Types の開発が追いつかないとそもそもテストが書けませんが、Terratest は AWS 公式のライブラリ 'aws-sdk-go' に沿ってテストを書くのでその心配は必要なさそうです。また Terratest は Terraform によるデプロイとテスト、その後のインフラの削除まで自動で行ってくれるツールですが Awspec は Terraform でデプロイした結果をテストするツールということで、その辺りの違いもあるようです。また Terratest は Terraform コードの output 文で得られた値もテストに利用できます。

一方で Awspec は Test-Kitchen (https://github.com/test-kitchen/test-kitchen) と Test-Kitchen の Terraform Driver である Kitchen-Terraform (https://github.com/newcontext-oss/kitchen-terraform) と組合せて、下記の URL にあるようなことも出来るようです。

Terraform デプロイし tfstate の状態と同一になっているかテストする例

これは 'terraform-aws-modules/terraform-aws-eks' という EKS の Terraform Module なのですがその中のファイル 'test_eks.rb' で下記のように記述されていて

require 'awspec'

# rubocop:disable LineLength
state_file = 'terraform.tfstate.d/kitchen-terraform-default-aws/terraform.tfstate'
tf_state = JSON.parse(File.open(state_file).read)
region = tf_state['modules'][0]['outputs']['region']['value']
ENV['AWS_REGION'] = region

これは Terraform デプロイした結果として得られる tfstate ファイルの通りに AWS インフラがデプロイされているかどうかを Awspec でテストしているように見えます。(まだ手元で動かしたわけではないので間違っていたら指摘頂けると助かります)

また、このテストを実行している .kitchen.yml ファイルは下記のようになっています。

---
driver:
  name: "terraform"
  root_module_directory: "examples/basic"

provisioner:
  name: "terraform"

platforms:
  - name: "aws"

verifier:
  name: "awspec"

suites:
  - name: "default"
    verifier:
      name: "awspec"
      patterns:
      - "test/integration/default/test_eks.rb"

まとめ

Golang でテストを書くのか Rspec DSL でテストを書くのか、それによって選定してもいいですし、CI/CD のパイプラインの中でテストをどう自動実行するかを考慮して選定してもいいと思います。READYFOR では CI/CD に CodeBuild, CodePipeline を使っているので、その中でどう処理出来るのか、これから検討していきたいと思っています。