TECH PLAY

株式会社スタメン

株式会社スタメン の技術ブログ

247

こんにちは、スタメンでバックエンドのエンジニアをしている河井です。 今年の3月に AWS 認定ソリューションアーキテクト-アソシエイト(SAA-C01)を受験し、合格したので勉強した内容や受けて良かったことについて振り返りをしてみます。 ※現在は SAA-C02 が最新で、本記事で紹介する動画や模試もアップデートされて対応済みです 受験の理由 AWS の基本的なサービスを体系的に理解するためです。 スタメンに新卒入社して以来 Rails や React を用いた開発を経験しましたが、 AWS はあまり触る機会がありませんでした。 その後バックエンドグループの所属になり、TUNAG の機能開発に加えて クラウド インフラの運用やパフォーマンス監視業務にふれることになりました。 普段の業務で AWS 関連の会話がかなり増えましたが、内容がわからないことも多かったです。 もちろんその都度サービスについて聞いたり調べたりするものの、断片的な知識を集めるのではなかなか包括的な理解が難しいと感じていました。 そこでまずは試験を受けて広く基礎知識をつけようと考えました。 受験時の経験 受験を決めたときのエンジニアとしての経験は ウェブエンジニア歴2年弱 Rails 、React などアプリケーションの開発経験がメイン AWS は ETL 基盤の改善で少し触ったことがある(CloudFormation、Lambda、Glue、 Kinesis など) AWS 認定以外も含め資格試験の経験なし といった感じです。認定試験によく出る範囲の経験はほぼありませんでした。 勉強したこと 何を使ってどんなことを勉強したのかを紹介します。 使ったのは大きく3つで、試験対策本、動画、模擬試験です。 試験対策本 試験対策本は、 SBクリエイティブ の AWS 認定資格試験テキストを使いました。 SAA 向けと、基礎レベルの クラウド プ ラク ティショナー(CP)の2冊です。 www.sbcr.jp www.sbcr.jp まずは CP の対策本を一通り読みましたが、思ったより簡単だったのですぐに SAA の方に切り替えました。 CP の試験を受ける予定はなくても、基礎の基礎を抑えた上で SAA に必要な知識を積み上げられるので読んで損はないと思います。 どちらの本についても内容を細かく覚えようとせず、どんな内容について理解すれば良いのかを把握するためにざっと読みました。 動画教材 本だけだとイメージが湧きづらい、とはいえすべてのサービスを触るほど時間はかけられないという理由から動画教材を使うことにしました。 今回はたまたまツイートで見かけた Whizlabs を選びました。 安かったのと時間がなかったので特に調査や比較などはしていないです。 www.whizlabs.com こちらも最初は全容を把握する目的で1.5〜2倍速で流しました。 各サービスの使い方が動画でわかるので実際に触らなくてもなんとなく感触をつかむことができます。 わかりにくい部分に関しては動画に沿って手を動かしながら理解を深めました。 模擬試験 公式の模擬試験は本番より難易度が低いと聞いていたので使わず、よくおすすめされている Udemy の以下のものを使いました。 【SAA-02版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集(6回分390問) 僕が受けたのは C01 のときだったので5回分(6個目は C02 の対策として追加された)で、中難易度1つ、高難易度4つの構成でした。 順番としては高難易度の4つを先にこなし、受験の前日に中難易度の試験問題を解きました。 試験後に領域別で得点率を出してくれることと、各設問の各選択肢について解説がついているのが非常に勉強になります。 この解説を読みながら、どうすれば正解の選択肢にたどり着けたのかを考えました。 知らない知識があれば本や動画にもどって復習します。 本や動画で流す程度に留めた理由はここで、実際の現場に近いシーンの中でどういうニーズがあってこの機能があるのか?を知った上で知識をつけたほうが効率的かつ実践的です。 知識としては知っていたのに間違えたというときは Well-Architected フレームワーク に沿って考えられていたかどうかを確認しました。 これを繰り返すことで自然と Well-Architected フレームワーク についても理解が深まりました。 受験の効果 一番実感したのは、やはり普段の業務での会話や資料で AWS 関連の話題が出てきたときに何についてのサービスなのか、なぜそれについて話題にするのかを理解できるようになったことです。 また、わからないことがあってもキャッチアップまでのスピードが速くなりました。 以下はスタメンの事業(TUNAG本体、TUNAGのETL基盤、TERAS)で使っているサービスです。 これらの中で試験本番や試験勉強を通じて見なかったのは Glue だけです。(Glue も見落としていたり他の練習問題などで出てきたりする可能性はあります。) 他の点として、設計のベストプ ラク ティスについても理解が深まったので、既存の設計についても改善すべきところを判断できるようになりました。 本番 本番の試験は Udemy の講座で練習した通りの形式だったので特に戸惑うことはなく、難易度についても Udemy の高難易度試験と比べると簡単でサクサク解いていくことができました。 この点でも模試で訓練しておくことは重要だと思います。 まとめ AWS SAA 受験の振り返りをしました。 個人的に思っていた以上の効果があり受験してよかったですし、同じような課題を感じている方にもおすすめしたいです。
こんにちは、スタメンでモバイル アプリ開発 をしている @temoki です。 スタメンに入社した当時は私一人でモバイル アプリ開発 をしていましたが、おかげさまでこの一年半で仲間も増え、組織上もモバイルアプリグループが発足するにまで至りました。そのため、最近はチームで一緒になって開発を進めていける喜びを感じつつ、複数人でも開発をスムーズに行うための環境づくりも進めています。 その一つとして、このたびモバイル アプリ開発 におけるCI/CDサービスとして Bitrise を採用したため、その背景や理由についてお伝えしたいと思います。 背景と目的 CI/CDサービスを導入を検討しはじめた目的はこの三つです。 リリースの頻度を上げたい 私がいなくてもデプロイできるようにしたい ユニットテスト を定着させたい それぞれの目的についての背景は次のとおりです。 リリースの頻度を上げたい ストアへのリリースはだいたい月に一回というペースで行ってきましたが、メンバーが増えたことで開発スピードも上がり、一回のリリースでの変更量が大きくなったことがリリースへの不安につながってきました。そのため、社内へのテスト配信の頻度をあげたり、ストアへのリリースをより小さく、より頻繁に行う必要があります。 また、せっかく開発は完了している機能があるのにユーザーへの提供が遅くなってしまったり、逆に遅くならないために直近のリリース予定日での機能の詰め込みということも起きるようになってきました。 私がいなくてもデプロイできるようにしたい デプロイ作業自体は fastlane や Gradle によりほぼ自動化してありましたが、アプリ署名のための秘匿情報の管理の観点から、その作業は私の開発機のみで行うようにしていました。しかし、その回数が増えてくると、実行の手間や実行のために開発機のリソースを取られることで、自分の作業に影響がでてきました。 そもそも、チームでの開発となった今、私しかデプロイを行えないということ自体が問題です。 ユニットテスト を定着させたい リリースへの不安を減らすために ユニットテスト の文化を定着させていきたいと思っている中、改修により既存の ユニットテスト が壊れていることに気づくのが遅れるということが起きてしまいました。幸いにも ユニットテスト のビルドが通らなくなっているだけで、テスト自体でエラーが起きるようなことではありませんでしたが、やはり定着させるためには常にテストが実行される環境が必要だと再認識しました。 候補の選定と検証 iOS アプリのビルドを行える macOS をサポートしていることを条件に候補を絞りました。以下が候補に挙がったサービスとその理由です。 GitHub Actions : macOS の無料枠がある Bitrise : モバイルアプリに強いと評判 Circle CI : TUNAG ウェブアプリケーション の開発で使用中 これらをウェブサイト上で機能表を比較してみても大きな差はないため、まず実現したいと思っている次のようなワークフローを作成して比較してみることにしました。 GitHub リポジトリ の特定のブランチへのプッシュをトリガーに、アプリをビルドして Firebase App Distribution で社内配信する 手動のトリガーで、アプリをビルドしてストアへアップロードする GitHub の Pull Request をトリガーに、 ユニットテスト を実行する 以降に記載する比較結果は2020年3月時点のもので、 ソースコード が GitHub のプライベー トリポジ トリにある前提のものとなります。 GitHub Actions GitHub Actions は GitHub Universe 2018 で発表され、2019年末に正式リリースされたばかりの、 GitHub 製CI/CDサービスです。リリースのニュースを聞いた時はモバイルアプリ向けのサポートは先になるだろうと思っていたのですが、プラットフォームとして macOS も含まれ、 iOS や Android のビルドツールもサポートされるなど、良い意味で裏切られたので注目していました。 しかも、 macOS でも 無料枠 ( GitHub Freeプランの場合は2000分、Proプランの場合は3000分の利用時間)があるため、最初に試してみるのは GitHub Actions にすることにしました。 以下にその結果を ○△× でまとめました。 ○ : macOS でも無料で利用できる枠がある ○ : モバイルアプリ向けに必要な環境も充実している Software installed on GitHub-hosted runners ○ : モバイルアプリ向けのアクションも比較的揃っている印象 △ : アクションは YAML 形式のコードでのみ定義できる β版の時は Visual Editor があったが正式リリース時に廃止されたようです △ : ビルドに必要な秘匿情報は GitHub の Secrets に文字列として配置できる iOS のプロビジョニングファイルや、コード署名用証明書などを扱うには一手間かかる × : macOS 環境が高額 Linux の10倍で利用時間を消費するため、 Proプランの場合は実質300分しか無料で利用できない × : 手動でビルドを開始する公式の方法がないのでアクション構築のトライ&エラーがやりにくい GitHub API で 外部イベント repository_dispatch を起こすことで代用できるが面倒。このトリガーではCarthageのキャッシュが利用できないなどの難点も。 一通りのトライアルを終えてみて、×に挙げた部分が運用上のネックとなりそうなことがわかりました。特に、 iOS において ipa ファイルを出力するまでには(Carthageのキャッシュが利用できたとしても)20分くらいはかかる現状もあり、利用時間(=費用)を気にしながら運用することになりそうです。 Bitrise 次は Bitrise です。Bitrise はモバイルアプリ向けのCI/CDサービスを謳っており、日本開催のモバイルアプリ向けのイベントにもよく出展されているため本命のサービスです。BitriseでもFreeプランで macOS を利用可能ですが、1ビルドあたり10分という制約があり、現状のアプリの ipa ファイル出力までを試すには時間が足りないことがわかっていたため、 GitHub Actionsの後に試すことになりました。 今回、検証のために Developerプラン を契約しています。このプランでは、一回のビルドあたり45分制限がありますが、ビルド回数に関わらず定額であるため、利用時間を気にせずに試すことができました。以下が、Bitriseの結果です。 △ : Freeプランでは1ビルドあたり10分の制限があり、 iOS アプリのビルドを試すには厳しい ○ : 定額であるため、利用時間を気にする必要がない ○ : モバイルアプリ向けに必要な環境が充実している ○ : リポジトリ 構成を自動でチェックしてワークフローをある程度自動で構築してくれるため、初期セットアップが楽 ○ : UIがわかりやすい(そしてかわいい) ○ : ワークフローをビジュアルでも YAML 形式のコードでも定義できる ○ : モバイルアプリ向けのアクションが豊富にある ○ : ビルドに必要な秘匿情報はアプリケーションごとに定義でき、かつモバイルアプリとの親和性が高い iOS のプロビジョニングファイルや、コード署名用証明書を設定するための専用の機能がある ○ : 困った時は 仮想マシン に ssh や リモートデスクトップ でログインして状況を確認することができる BitriseのUIはポップでかわいい😍 評判が高いのも納得のクオリティでした。 GitHub Actionsの時には試行錯誤しながらセットアップしていましたが、Bitriseではとても簡単にセットアップを終えることができました。また、定額なのでその後もアプリの社内配信や ユニットテスト をどんどん実行でき、利用時間を全く気にしなくていいのが素晴らしいです。 Circle CI TUNAG ウェブアプリケーション の開発ですでに社内で利用中の Circle CI も候補に挙げましたが、モバイルアプリ向けに想定している実行時間や頻度を考えると、その開発業務にも費用にも大きな影響を与えそうということがわかりました。そして何よりBitriseが想像以上に優秀だったことから、Circle CIの検証はせず、Bitriseを継続していくことに決めました。 さいごに 最後にまとめとなりますが、一言で言えば 「Bitriseはいいぞ!」 です。業務上の選定となるため機能面での比較を真面目に行いましたが、Bitriseを使っているうちに、そのビジュアルデザインのかわいさ、操作性の良さ、細かい部分でのユーザーへの配慮を感じられ、純粋にBitriseというプロダクトを心から気に入ってしまいました。 Continuous happiness ✨ そして、弊社の創業事業TUNAGもエンドユーザーに同じように心から気に入ってもらえるようなプロダクトに育てていきたいと強く思いました。そのためにはさらに強い開発力が必要となりますので、スタメンでは一緒にプロダクト開発を進めてくれる仲間を募集しています!興味を持ってくれた方は、ぜひぜひ下記のエンジニア採用サイトをご覧ください。 スタメン エンジニア採用サイト サーバーサイドエンジニア募集ページ フロントエンドエンジニア募集ページ インフラエンジニア募集ページ モバイルアプリエンジニア募集ページ
スタメンのデザイナーの @kiyoshifuwa です。 現在、 弊社のデザイナーは社員のわたし1名、学生アルバイトさん1名の計2名です。 主にTUNAGなど各事業のアプリケーションのデザインを行っていますが、実は社内のあれこれも、社内のデザイナーが作っています! 今回の記事では、社内業務の一部をご紹介します。 社外の方に向けて 各種Webサイト 規模の大きいものは外部協力会社様にお願いすることもありますが、小規模であれば社内でデザイン・実装を行います。昨年はTUNAGブランドサイトのトップページ、エンジニア採用サイト、 インターンシップ 募集サイトのデザインをしました。 案内パネル スタメンの セミ ナースペースでは様々なイベントや勉強会が行われます。来社されたお客様をご案内するために、 Wi-Fi とお手洗いのパネルを作りました! 社外報 社員のご家族に、社長の想いや社員の活躍、イベントの様子などを知っていただくために作っています。このような冊子のデザインは、スタメンに入るまでやったことがありませんでした。一から勉強して、試行錯誤しながら作り上げています! ▼新メンバーや各拠点のオフィスを紹介するコンテンツです! スタメン社員に向けて 行動指針ポスター スタメンには6つの行動指針があります。新メンバーでもすぐに馴染み浸透するように、みんなが忘れずに意識できるように、それぞれの指針にあったビジュアルを作り、ポスターにしました。 ▼もちろん名古屋本社だけでなく東京、大阪オフィスにも 掲示 されています!  ▼Enjoy Togetherの人々の中に、実はマネジメントメンバーがいます。こっそり遊び心を加えています! スタメンアワード受賞者ポスター 期ごとに最も活躍したメンバーを表彰する「スタメンアワード」を受賞したメンバーを称えるポスターです!こちらももちろん全拠点に 掲示 されます!常に目に入る位置に 掲示 されているので、日々「次は自分が受賞できるよう頑張るぞ🔥」と思えます。 ▼2019年3rdピリオド 新人賞を受賞したこうきです。おめでとう! 他職種メンバーのお手伝い 社内勉強会 セールスやエンジニアにもデザインやツールの知識が役立つことがあります。「わかりやすいスライドの作り方」や、「 Keynote を効率よく使う方法」などノンデザイナー向けの社内勉強会を自主的に行っています! 登壇資料テンプレート スタメンには職種を問わず自主的に外部発信をする人がとても多いです。資料作りを楽にするため、また他社の方にスタメンの資料だと認識してもらうためにテンプレートを作りました!思ったより社内から反響があったので、作ってよかったな〜と思いました☺️ 実はこんなものもデザインしています 社内イベントを盛り上げるためのデザインも作っています! ス タツ ク 社内横断型の組織活性化PJチーム「ス タツ ク」歴代メンバーを紹介する画像です!撮影は社内で本格的に行いました。 TUNAG用スタンプ スタメンでは、自社で開発している「TUNAG」でコミュニケーションを取っています。投稿へのコメントやチャットでのリアクションにオリジナルのスタンプを使うことができます。たくさんありますが、一部をご紹介します! TUNAG用組織画像 「TUNAG」では、組織の構成も見ることができます。各部署、個性が出まくりの写真をカバー画像に設定しています。プロダクト部では、「強いエンジニア・デザイナー・ディレクター」をテーマにヒーロっぽい画像を簡易的に作りました!背景の爆発はから揚げを加工してできています。 おわりに 以上、スタメンでの社内業務をご紹介しました。 印刷など、全然知識のない不慣れな分野でも自分で調べながらやるしかないので、なかなか大変なこともあります(笑) でも毎回、スタメンのみんなへサプライズを仕掛けているような気持ちになってわくわくします!また、お披露目した後の反応を見るのも嬉しく、やりがいを感じます。困難を乗り越えて、みんなに感動を届けるのはとても楽しいです💪 スタメンにお越しいただく際はぜひ、デザインもご覧になっていってください!
こんにちは。松谷( @uuushiro )です。 先日コーポレートサイトにて、 新経営体制のお知らせ を公開させていただきましたが、3月より取締役CTOを務めていた小林 一樹が常務取締役VPoEに就任し、 執行役員 CTOには私、松谷 勇史朗 が就任しました。CTO と VPoE を分離することで、小林はVPoEとして組織と事業に、私はCTOとして技術に専念し、組織・事業・技術の意思決定の速度と精度の向上を実現していきます。 今回の就任にあたりまして、私自身の振り返りとこれからの抱負を簡単に述べさせていただきたいと思います。 まず私とスタメンとの関わりですが、スタメンが創業した2016年に学生 インターン として加わり、翌年正社員として入社しました。入社時の記事は こちら です。エンジニア未経験で ベンチャー に飛び込み、今までひたすら業務の中で経験を積ませてもらいました。入社時には自分がCTOとして役割を担うことになるとは想像もしていませんでしたが、創業期はCTO小林の直下で学んでいたので、自然とCTOという役割を意識していたのも確かです。ただ自分としてのCTOのイメージは漠然としていて、「CTOになりたい」と言ってはみても、そもそも「CTOってなんだろう?」「なりたくてなっていいものなのか?」などなど自問自答を続けていました。 そんな中、入社2年目にテッ クリード として技術的な意思決定に関わるようになり、3年目にはマネージャーとして開発チームの運営に関わるようになりました。テッ クリード として、マネージャーとして、どうやったらスタメンに貢献できるか、中長期で私ができることは何なのか、ということを考え続けていたその延長線上にCTOというイメージが徐々にはっきりしてきました。まだまだ手探り状態ではありますが、CTOとしてスタメンに貢献できる姿に確信を持てるように、自分のあるべきCTO像を考え抜いていきたいと思います。 実際に就任してみると、失敗を誰のせいにもできない緊張感、意思決定の影響の大きさ、経営陣としての責任の重さに、ただただ身が引き締まる思いです。正直、前CTOの小林や、社外のCTOの トップランナー の方たちを見ていると同じCTOとして焦りしか感じませんし、今後は自分の限界値が組織の限界値になるプレッシャーを感じています。今はまだまだ理想とは程遠いですが、とにかく自分の成長を止めずに少しでも前進し成果を出していきたいと思います。 今後の技術的課題としては、事業の成長を加速させられるような開発スピードとクオリティの維持、事業規模拡大に備えたスケーラビリティの確保、安心してサービスを利用していただける堅牢なセキュリティ、非連続な進化を遂げるための新しい技術投資、などなど挙げればキリがありませんが、スタメン開発チームのビジョン「エンジニアリングで事業の成長を牽引する」に徹底的に向き合い、チームで前進していけるようにCTOとしてリードしていきたいと思います。 組織としては、スタメンエンジニアの価値観 Star Code にある通り、常にユーザー目線で考え、障害やプロジェクト遅延などの失敗に向き合い、お互い忖度せずに本音で語り合い、日々の自分の仕事に誇りを持てるほどのプロ意識を持ち、そして何よりもエンジニアリングを楽しむ。そんなエンジニア組織をCTOとして皆とつくりあげていきたいです。 社内外問わずスタメンのCTOとして納得してもらえる実力をつけ実績を出せるように、全力で役割を全うしていきたいと思いますので皆様よろしくお願いいたします。 最後に スタメンエンジニア組織としては、0→1 そして 1→10 のフェーズを終え、これからはその先のフェーズ10→100のフェーズになります。プロダクトが複数になり、TUNAG の大規模化と機能拡張に向けて一層強化を進めていくタイミングなので、とてもやりがいのある面白い仕事になると思います。新しい体制で、多くのチャレンジングな技術的課題に向き合い、ユーザーに価値を届けるエンジニア募集しています!興味を持ってくれた方は是非、下記のエンジニア採用サイトを見てください。 スタメン エンジニア採用サイト サーバーサイドエンジニア募集ページ フロントエンドエンジニア募集ページ インフラエンジニア募集ページ モバイルアプリエンジニア募集ページ
こんにちは、スタメンでバックエンドのエンジニアをしている河井です。 私の所属するバックエンドチームでは、普段からサービスのパフォーマンス監視とチューニングを継続的に行っています。 今回は、データベース負荷のモニタリングに使っている Performance Insights というツールの活用方法をまとめてみます。 Performance Insights について Performance Insights(パフォーマンスインサイト)とは、Amazon RDS で提供されている機能で、DB の負荷のモニタリングが簡単にできます。 ざっくりとまとめると、 指標がシンプルなので DB の負荷状況を直感的に把握できる SQL クエリが表示されるため問題箇所の特定がしやすい リアルタイム更新なので即座に負荷内容を分析できる といったメリットがあります。 有効化については こちら を参照ください。 ダッシュボードの見方 ダッシュボードが見やすくて便利なので、基本的にこちらを使います。 RDS コンソールのサイドバーにある「パフォーマンスインサイト」からアクセスできます。 画面は3つのパートに別れていて、上から、カウンターメトリクス、データベースのロード、SQL ステートメントダイジェストとなっています。 基本的にはデータベースのロードとSQLステートメントダイジェストを使うので、この2つについて解説します。 データベースのロード データベースの負荷を時系列で表示しています。負荷は平均アクティブセッション(Average Active Session、AAS)という指標で表現されています。 平均アクティブセッションとは、一定時間内に処理中または処理開始を待ちのセッションの数で、この数が多いほど DB に負荷がかかっているといえます。 上記画像では、スライス基準という項目が、「待機」 になっています。 スライス基準とは AAS の内訳を何基準で表示するかという設定項目です。 待機基準では、データベースの一連の処理のうちどのイベントでどのイベントでの待機時間が長くなっているかを知ることができます。 各種イベントの詳細については こちら を参照ください。 グラフの上部にある破線は今見ている RDS インスタンスの仮想 CPU 数を表しています。 CPU での待機数だけでこのラインを超えると、CPU 数が不足しているといえます。 上の画像では一箇所そのラインに到達していますが、待機の内訳を見ると CPU の割合は低いです。 そのため、CPU が原因となって負荷が高まっているわけではないと判断できます。 次に、スライス基準を SQL に変えてみます。 SQL 基準を選択することで、各クエリごとにどれだけ待機しているかを知ることができます。 ぼかしを入れてあるところには SQL クエリが表示されており、どのクエリによって負荷が発生しているのか?を判定できます。 SQL ステートメントダイジェスト SQL ステートメントダイジェストでは、 簡略化された SQL クエリが負荷の高いものから順に表示されています。 ダイジェストではパラメータが name = ? のように置き換えられており、同じクエリの影響をまとめた値になっています。 さらに詳細を見たいときは▷をクリックし、実際のパラメータが入った個々のクエリを見ることができます。 TUNAG では企業ごとに柔軟な設定が可能なため、予期せぬ設定で負荷が高まることがあります。 パラメータありの状態でクエリを見て企業を特定し、原因究明までスピーディに行えるようになりました。 監視の設定 上記は負荷がかかっているタイミングが特定できている前提で話をしていました。 負荷が高まっていること自体に気づくために、データベースのロードが一定数を超えたら通知されるようにしてみます。 設定可能な項目 CloudWatch Alarm でデータベースのロードを監視することができるので、設定手順を説明します。 データベースのロードに関するメトリクスは3種類あります。 DBLoad DBloadCPU DBLoadNonCPU DBLoadCPU は待機要因を CPU のみに限定したもの、DBLoadNonCPU は CPU 以外の要因で待ちが発生しているもの、DBLoad はその合計値となっています。 バックエンドチームでは次のような使い分けをしています。 DBLoadCPU: CPU 数不足の検知 DBLoadNonCPU: 非効率なクエリ発行の検知(インデックスが効いていない、DB への同時アクセス数が多すぎるなど) 設定手順 どの指標を使うにしても設定は同じなので、DBLoad のアラームを設定してみます。 まずは CloudWatch コンソールにアクセスし、サイドメニューの「アラーム」を選択、「アラームの作成」と進みます。 進んだ先の画面で、"DBLoad" で検索→「RDS > データベースメトリクス」を選択→監視したい DB インスタンスにチェック→メトリクスを選択と進みます。 メトリクスを取得する間隔や閾値は、普段負荷が高まるときの AAS を参考に決めましょう。 最後に、通知先を設定して終了です。 まとめ Performance Insights のダッシュボードの見方からアラートの設定方法までざっくりとまとめてみました。 これを使い始めてから劇的にクエリの改善が進んだので、まだ使っていないという方はぜひ触ってみてください。 最後に、株式会社スタメンでは一緒に働く仲間を募集しています。 ご興味のある方はぜひ下記のページをご覧ください! エンジニア採用サイト エンジニア募集ページ(Wantedly) 参考資料 パフォーマンスインサイトを使用する Performance Insights で Amazon RDS for MySQL をチューニングする アイキャッチ Photo by Chris Liverani on Unsplash
スタメン エンジニアの松谷( @uuushiro )です。 スタメンは、2020年3月より エンゲージメント診断サービス TERAS(テラス) の提供を開始します。創業プロダクトである TUNAG(ツナグ) に続いて2つ目のプロダクトになります! TERASは、エンゲージメント経営を実行できるサービス TUNAG のノウハウを元にした、組織のエンゲージメントを可視化する組織診断サービスです。サービスの概要は以下リンクからご覧ください! エンゲージメント診断サービス『TERAS』をリリース この記事では、エンゲージメント診断サービス TERAS の技術 アーキテクチャ の紹介をします。 TERAS は SPA(React)と API サーバ( Ruby on Rails )で作られたWebアプリケーションです。 アーキテクチャ の構想・実装にあたって、重要視した点は3つです。 実装・保守・運用コストをなるべく削減し、機能開発に集中できる基盤にしたい セキュリティ・スケーラビリティなどの非機能要件は初期からなるべく妥協したくない インフラをコード化して管理し、インフラ知識の 冗長化 のハードルを下げたい。また、再利用性をあげたい。 特に複雑なことはしておらず、結果としてシンプルな構成になりました。 以下で アーキテクチャ の全体図と個別詳細を紹介していきます。 TERAS アーキテクチャ 全体図 TERAS アーキテクチャ の全体図は以下になります。 ざっくり以下の項目に分けて紹介していきます。 ネットワーク CDN WEBサーバー デプロイ 秘匿情報管理 インフラのコード化 ネットワーク ネットワーク以下3つのサブネットに分けています。 グローバルIP を持てば、外部ネットワークと通信ができるサブネット(Public Subnet) NATを介してのみ外部ネットワークと通信ができるサブネット(Protected Subnet) 外部ネットワークと通信はできないサブネット(Private Subnet) TERAS では、Application Load Balancer を Public Subnet に配置し、ECS/Fargateタスクを Protected Subnet に配置することで、Application Load Balancer からのみアクセスを受け付けるようにしています。また、WEBサーバーとしてFargateタスクを利用していますが、Fargateタスクに対して直接Elastic IPを割り当てることができないので、外部へのアウトバウンド通信(メール配信サービスへの API アクセスなど)を許可するために、NATを Public Subnet に配置しています。RDSは、外部通信の必要性がないので、Private Subnetに配置しています。このように、ネットワークの役割毎に作成することで、階層化したアクセス制御を行いセキュリティを向上させています。 CDN TERAS では、 CDN として Amazon CloudFront を利用しています。導入理由は3点です。 パフォーマンス向上 エッジサーバーからコンテンツが送信される分、レスポンスが速い ただ、オリジンが東京リージョンなので実際にはそこまで差がでないかもしれない。 コスト削減 Amazon CloudFront からデータを送信するコストは Amazon S3 から送信するコストよりも安い セキュリティ AWS WAF の統合が可能で、 XSS や SQLインジェクション などの一般的なWEBアプリケーションの攻撃を防ぐことができる。(2019年11月に新しくリリースされた AWS WAF V2 の Managed Rule を利用し、WAF V1に比べ、ルールの設定が大幅に楽になった。) Amazon CloudFront は、世界中にノードがあるため大量の 帯域幅 があり、多くの DDOS攻撃 を軽減できる また、 Amazon CloudFront に関して、SPAにおける要件や、セキュリティの観点で対応した事項があるので以下で紹介します。 キャッシュコン トロール Amazon CloudFront のキャッシュコン トロール 機能(Behaviors)を活用し、 Amazon S3 (SPAサーバー)と Application Load Balancer ( API サーバー)のマルチオリジン構成にしています。クライアントからのリク エス トパターンを元に、キャッシュポリシーやオリジンへのアクセスルールを個別設定しています。TERAS では、 /api というリク エス トパターンの場合は、Application Load Balancerへ、その他のリク エス トパターンは Amazon S3 へ振り分けられるように設定しています。 また、 /api のような動的コンテンツに関しては、キャッシュされないように TTL を0に設定しています。 カスタムエラーページ React RouterなどSPA側でルーティングをしている場合、サブ ディレクト リ含むURLでブラウザをリロードをすると、S3のエラーページが表示されてしまいます。これは対象の ディレクト リがS3 バケット に存在しないことが原因です。 Amazon CloudFront の Error Pages に403または404エラーの場合には /index.html へ転送し、SPA側でルーティングの制御が行えるようにしています。 オリジンサーバーの保護 セキュリティ・パフォーマンスの観点において、外部から直接オリジンへアクセスされることを防ぎたいです。 Amazon S3 には、ブロックパブリックアクセスという、あらゆるルールより優先されるアクセス制御ポリシーがデフォルトで有効化されています。設定ミスなどデータが意図せず公開されることを防ぐために、基本ブロックパブリックアクセスは有効化のままで運用できるようにしたいです。 Amazon CloudFront の Origin Access Identity を使うことで、 ブロックパブリックアクセスを有効化したまま、 Amazon S3 へのアクセスを Amazon CloudFront からのリク エス トに限定することができます。 また、Application Load Balancer についても、 Amazon CloudFront でカスタムヘッダを追加し、Application Load Balancer側で値が一致すれば、CloudFrontから転送されてきたリク エス トとみなし、リク エス トを許可することができます。これによって、Application Load Balancer についても Amazon CloudFront からのリク エス トに限定することができます。 クロス ドメイン 通信が不要 SPAと API サーバが連携するアプリケーションを ホスティング する場合、SPAサーバーと API サーバーが別 ドメイン で ホスティング されることがあると思いますが、 Amazon CloudFront でマルチオリジン対応することで、同一 ドメイン で扱うことができ、 API サーバー側におけるCORS対応が不要になります。実装・検証 工数 を抑える1つの要因となりました。 WEBサーバー AWS Fargateを以下の理由で導入しました。 ホスト インスタンス の管理から解放 オートスケールの設定が不要 つまり、自分でサーバーを管理することなくコンテナを実行できます。EC2に比べて、コストは割高ですが人的 工数 の削減を考えると元が取れるのではないかと思います。 AWS Fargate については、以下の AWS Startup ブログ が大変分かりやすかったので興味のある方はそちらをご覧ください。 スタートアップのためのコンテナ入門 – AWS Fargate 編 デプロイ API サーバー( Amazon ECS) AWS CodePipeline で AWS CodeBuild と AWS CodeDeploy を連携しデプロイをしています。以下の理由で導入しました。 デプロイサーバーの構築・運用コスト削減 オートスケールとの相性が良い ECSとの統合機能が充実している Blue Green Deployment Canary Deployment Linear Deployment AWS 内でデプロイフローが完結することで、 AWS の認証情報などを外部に公開する必要がなくセキュアに まだ、 AWS CodePipeline関連のサービスの利用経験が浅いので課題が見つかるかもしれませんが、セキュリティ・スケーラビリティの観点や他 AWS サービスとの親和性においても良い選択なのではないかと思っています。 SPA( Amazon S3 ) AWS CodeBuild でビルドし、その生成物を S3 sync して、 Amazon CloudFront の invalidate を実行しキャッシュをクリアするだけです。 秘匿情報管理 System Manager の Parameter Store 秘匿情報を登録することで、 AWS CodeBuild、 Amazon ECS で 環境変数 に機密情報を渡せます。 Rails のcredentials機構を使うよりも楽で、ビルドやデプロイ時など必要な秘匿情報も合わせて一元管理できるのでとても便利でセキュアだと感じています。 インフラのコード化 これらの構成を AWS CloudFormation で作成しています。 AWS CodeDeploy のECS Blue Green Deployment については、未だ AWS CloudFormation 対応していないため、マネジメントコンソールから手動で登録しています。 この アーキテクチャ は、プロダクト固有の特殊な構成ではないので、今後 WEBアプリケーションの基盤構築の際に、再利用しやすくなっています。そして、今後新しく TERAS へ参加するメンバーもこの記事とインフラコードを見れば、全体像を把握することがでるので、システム知識のキャッチアップが速くなるのではないかと期待しています。 まとめ TERASの全体像と各項目について紹介させていただきました。インフラ構築・運用コストを抑え、かつセキュアでスケールするシステムを作る際の参考になれば幸いです。この構成はシンプルで、汎用性も高く、かつコード化をしているので、今後プロダクトが増えた際にも、割と簡単に再利用ができるのではないかと期待しています。 3月にリリースされ運用が始まりますが、まだまだ課題はたくさんあります。また、プロダクトが複数になったことで、セキュリティ・IAM管理・監視体制など、プロダクトごとにポリシーが乱立しないように、戦略立てて決めていく必要があるなと感じています。 最後に TUNAG、TERAS、新規プロダクトを横断的に設計・改善してくれるSREを募集しています! プロダクトが複数になり、TUNAG の大規模化に向けて一層インフラ面の強化を進めていくタイミングなので、とてもやりがいのある面白い仕事になると思います。興味を持ってくれた方は是非、下記のエンジニア採用サイトを見てください! スタメン エンジニア採用サイト インフラエンジニア募集ページ
皆様いかがお過ごしですか。スタメンでモバイル アプリ開発 を担当している @sokume です。 以前、 TUNAG iOSアプリの技術的な解説 で、 @temoki から発信していますが、読んでいただけましたでしょうか。今回の記事は Android 版の技術的な解説記事です。 言語 Google I/O 2019にて Kotlin-First 宣言があり、名実ともに Android の第1言語は Kotlin に変わりました。もちろんTUNAG Android アプリもすべて Kotlin で書かれています。 Kotlinも日々更新していますので、常に新しいバージョンに追従していける開発環境にしています。(記述時点ではv1.3.61ですね) アーキテクチャ ー Android Jetpack に含まれる、 Android Architecture Component をベースとした構成をとっています。 この構成をすべて利用するのでなく、TUNAG Android アプリに合わせた形で利用箇所の選定をしています。 サービス TUNAG は AWS + Ruby on Rails で構築していますが、mBaaS (mobile backend as a service) の Firebase を利用して以下の対応をおこなっております。 - Cloud Firestore 利用した即時性の高いチャット機能 - Authentication を利用したユーザー認証 - Crashlyitics を利用したクラッシュレポーティング - Cloud Messaging を利用したアプリへのプッシュ通知配信 - App Distribution を利用したアプリのベータ配信 (ここの点は TUNAG iOS と一緒の構成としています。) ライブラリ 前述の Android Jetpack や Android KTX はもちろん、 Material Components UI コンポーネント ライブラリを利用し、 Android に適したUIの実現を進めています。 HTTPクライアントは Retrofit2 と Okhttp3 を利用し、HTTPクライアントとからめて、 JSON パーサーは Moshi を利用しています。 画像の読み込みにもHTTPクライアントとからめて Picasso を利用しています。 (Square 製ライブラリが多めですね) Model層からのデータについてはリアクティブに処理するため、 RxKotlin / RxAndroid / RxJava を利用しています。 ReactiveExtensionを利用していますが、Activity/Fragment(View層)や ViewModel (ViewModel層)ではライフサイクル対応コルーチンスコープを利用し、ライフサイクルを意識した処理の制御が行える実装としています。 ベータテスト iOS アプリと同じく、スタメンのメンバー自身がTUNAGを利用しています。そのためアプリの新バージョンは常に社内メンバーでのテストを実施しています。 CIの仕組みは2019年11月に公開された Github Actions の利用を検討しています。 ワークフローという形で、 Github へのアクションを記述し、 Push や PullRequset といったユーザー操作をトリガーに、 ビルド実行 ➡ 配信 といった処理を継続的に実施する事ができます。 社内メンバーへの ベータテスト の配信は前述の Firebase App Distribution を利用して配信しています。 さいごに TUNAG Android アプリの構成を説明させていただきました。 TUNAG iOS アプリとはまったくの別のものとして考えず、同じ構成にすることで得られる利点などを考えた構成にしています。 もちろん、 Android アプリとして追求すべき点は妥協しません。 熱い仲間と一緒に、より良いサービスを一緒に作りませんか? 仲間を募集しています! まずは、スタメンのエンジニ アサイ ト stmn, inc. Engineers を見てみてください!
こんにちは! スタメンで Rails アプリの開発を担当しているシュール( @shule517 )です! Rails アプリケーションを安全に開発するために、自動テストはとても大切ですよね! スタメンではCircleCIで RSpec やRuboCopの実行をし、安全を確認して本番機へデプロイしています。 CircleCIの高速化を行った結果、倍速(約20分→10分)にすることができました!その時に対応したポイントを解説します。 CircleCIのキャッシュを有効活用! ① アセットプリ コンパイル 結果をキャッシュする CI全体の処理時間のうち4分の1はアセットプリ コンパイル に時間がかかっていました。アセットプリ コンパイル の結果をキャッシュすることで5分ほど高速化できました。 # プリコンパイルのキーを作成 - run : name : create assets precompile cache key command : | # プリコンパイル対象のファイルの最新コミット番号をキーにする git rev-parse $(git log --oneline -n 1 app/assets lib/assets vendor/assets Gemfile.lock | awk '{{print $1}}' ) > VERSION # キャッシュを復帰 - restore_cache : keys : # 同じバーションからキャッシュを復帰。無ければ、直近のキャッシュを復帰。 - assets-precompile-cache-{{ checksum "VERSION" }} - assets-precompile-cache- # プリコンパイルを実行 - run : name : assets:precompile command : | current_revision=VERSION previous_revision=public/assets/VERSION # プリコンパイル対象のファイルが変更されていなければスキップ if [ ! -e $previous_revision ] || ! diff $previous_revision $current_revision; then bundle exec rake assets:precompile cp -f $current_revision $previous_revision else echo "Skipped." fi # キャッシュを保存 - save_cache : key : assets-precompile-cache-{{ checksum "VERSION" }} paths : # プリコンパイル結果の保存先を指定 - public/assets - tmp/cache/assets ※実際に使用している設定ファイルとは異なります。 アセット関連のファイルが変更されていない場合はプリ コンパイル をスキップしたいため、キャッシュのキーをプリ コンパイル 対象のファイルの最新コミット番号にしました。また、アセット関連のファイルを修正している場合も、前回との差分だけをプリ コンパイル するようになるためかなり時間が節約できます。 プリ コンパイル の対象ファイルとして Gemfile.lock を入れている理由は、Gemをインストールした時にアセット関連のファイルが変更されることがあるためです。 アセットの変更がない場合、assets:precompileをスキップすることでCIの速度を改善した を参考にしました。 ② Gemのインストールをキャッシュする CircleCI上で使うGemをGemfileに記載し、インストールしたGemをキャッシュします。RuboCopの実行に必要なGemをキャッシュし、3分ほど速くなりました! group :test do # CircleCIでRuboCopを実行するために必要 # 修正前はCircleCIのタスクでgem installしていた gem ' rubocop ' gem ' rubocop-select ' gem ' rubocop-checkstyle_formatter ' end # キャッシュを復帰 - restore_cache : key : rails-gemfile-{{ checksum "Gemfile.lock" }} # Gemをインストール - run : bundle install --path vendor/bundle # キャッシュを保存 - save_cache : key : rails-gemfile-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle restore_cache / save_cache の keyを checksum "Gemfile.lock" とすることで、 Gemfile.lock の内容が一致した時だけキャッシュを復帰します。つまり、 Gemfile を変更した時だけGemのインストールが実行されます。 CircleCI - キャッシュ設定の例 を参考にしました。 ③ ソースコード のチェックアウトをキャッシュする ソースコード をチェックアウトした後の.gitフォルダをキャッシュします。これで前回との差分だけをチェックアウトすればよくなり、30秒ほど速くなりました! # キャッシュを復帰 - restore_cache : keys : - source-v1-{{ .Branch }}-{{ .Revision }} - source-v1-{{ .Branch }}- - source-v1- # ソースコードをチェックアウト - checkout # キャッシュを保存 - save_cache : key : source-v1-{{ .Branch }}-{{ .Revision }} paths : - ".git" restore_cache に指定する keys を複数指定しておくと、その中から一番近いキャッシュデータを復帰してくれます。今回の設定方法だと、同じブランチのキャッシュを優先し、無ければ直近のキャッシュを使用します。 CircleCI - ソースコードのキャッシュ を参考にしました。 RSpec をバランスよく並列実行する! ① ボトルネック になっているコンテナを見つける CircleCIのTimingを見ると、分散している各コンテナの実行時間を見ることができます。16分台に完了しているコンテナもありますが、1番遅いコンテナに足を引っ張られてしまい全てが完了するのは22分です。処理を均等に分割できれば、20分以内に減らせそうですね!遅いコンテナから順に分散を検討しましょう。 ② ボトルネック になっているspecファイルを見つける RSpec の実行ログを保存することで、コンテナごとの各specファイルにかかった詳細な時間を見ることができます。どのspecファイルが ボトルネック になっているかを見つけます。 - run : name : bundle exec rspec command : bundle exec rspec --format RspecJunitFormatter --out test-results/rspec.xml - store_artifacts : path : test-results/rspec.xml ③ RSpec を高速化し、 ボトルネック を解消する ボトルネック のコンテナ、テストファイルを特定したら、 RSpec の高速化をしていきましょう!高速化で対応した内容がこちらです。 不要なテストデータを作らないようにする 不要なテストデータ作成で、テストの実行が遅くなっていた 未使用なテストデータを作っているletを削除した 使い回さないテストデータの場合は、`let!`→`let`に変更した E2Eテストのitをまとめる 1つのitで1つのexpecにするのは RSpec として正しいが、E2Eテストでは時間がかかりすぎる 同じ画面を確認する場合は、itをまとめることで高速化した itの中で複数のexpectを実行する場合は、`aggregate_failures`を使う RSpecでテストをまとめて検証する方法 を参考にしてください。 E2Eテストのsleepを削除し、have_xxxで待つ 画面描画を待つためにsleepをしていたため、テストが遅くなっていた テストケースの数 × sleepの時間だけ無駄な待ち時間が発生してしまう sleepの代わりにhave_xxxマッチャを使い、待ち時間を最小限に抑えた 巨大なspecファイルを分割する RSpec の分散はテストファイル(*_spec.rb)ごとに行っている 高速化を行っても、テストケースが多いテストファイルは ボトルネック になってしまう そのため、巨大なspecファイルを分割し、均等に分散できるようにした おわりに CircleCIの高速化を行い、待ち時間が減ることで開発のストレスがかなり減りました!みなさんがCircleCIを高速化する時に、参考になればとても嬉しいです。待ち時間を減らして、より楽しく効率的に開発をしていきましょう! 熱い仲間と一緒に、より良いサービスを一緒に作りませんか? 仲間を募集しています! まずは、スタメンのエンジニ アサイ ト stmn, inc. Engineers を見てみてください!
こんにちは。スタメンでモバイル アプリ開発 をしている @temoki です。 スタメンには 誕生祭 という制度があり、メンバーの誕生日には同じ部署のメンバーでお祝いし、その様子を弊社が提供しているサービス TUNAG で全社に共有しています。現在アルバイトで今年の春に新卒入社を予定しているエンジニ アメンバー のために昨年に実施した誕生祭では、プロダクト部ならではの手作りのお祝いをしたので、その様子をお伝えしたいと思います。 計画 TUNAG にはメンバーの誕生日を事前にお知らせする機能があります。そのお知らせをトリガーに本人を除いたメンバーで社内のチャットグループを作り、そこでひっそりと準備が始まります。 スタメンの企業理念は 一人でも多くの人に、感動を届け、幸せを広める。 です。この理念について弊社代表の加藤は「感動は相手の期待を超えることで生まれる」とよく私たちに伝えます。この誕生祭でも期待を超えるお祝いができるように、その人が最近話していたことや、TUNAG のプロフィール、最近の投稿の内容などの情報を集めながら、プレゼントは何にするか?どうやって祝うか?のア イデア を出していきます。 今回お祝いするメンバーは Android アプリエンジニアです。彼のデスクにはドロイド君フィギュアを置いてあったり、個人でも Android アプリをリリースしていたりと、 Android アプリ開発 への愛がとても強いです。そこで、 Android をテーマに皆でア イデア を出し合い、最終的には次のように計画しました。 プレゼントは Boothのドロイド君キャップ そのプレゼントをドロイド君から渡す!? バースデーケーキの代わりに Android のこれまでのバージョンのコードネームとなったお菓子を全て揃える 準備 計画を元に、各メンバーが準備を進めていきます。プレゼントは発注するだけですが、残りの2つのア イデア が大変です。 ドロイド君ヘルメットを作る プレゼントをドロイド君から渡すために、ドロイド君なりきりヘルメットを作ることにしました。元ネタはコチラ( あのドロイドくんヘルメット、設計書付きで誰でも手作り可 )です。 東急ハンズ や100円ショップをまわって材料を集め、本人がいない時を狙って制作を進めていきました。 半球状とディスク状の発砲スチーロールを組み合わせて整形 ドロイド君の緑色に近い水性アクリル塗料で塗っていく 塗りムラがないように入念にチェック デザイナーの手で目を入れて命を吹き込む Android のこれまでのバージョンのコードネームとなったお菓子 Android は 2009年にリリースされたバージョン 1.5 から、頭文字がアルファベット順で始まるお菓子の名前が付けられています。毎年 Android の新バージョンのリリース時期が近づくと、 Android アプリ開発 者の間では次のバージョンのお菓子は何かを予測する話題で盛り上がりますね。 このコードネームが昨年リリースされた Android 10 で廃止されたこともあり、この誕生祭のお祝いのケーキの代わりに、これらのお菓子を全て揃えてみようということになりました。前日にメンバーでいろんなお店を回ってなんとか全て集めることができました。 参考 (List of Android version names) Android ver. お菓子 1.5 C upcake ( カップ ケーキ) 1.6 D onut (ドーナツ) 2.0, 2.1 E clair (エクレア) 2.2 F royo ( フローズンヨーグルト ) 2.3 G ingerbread (ジンジャーブレッド) 3.0, 3.1, 3.2 H oneycomb (はちみつ) 4.0 I ce Cream Sandwich (アイスクリーム・サンドイッチ) 4.1, 4.2, 4.3 J elly Bean (ジェリー・ ビーン ) 4.4 K itKat ( キットカット ) 5.0, 5.1 L ollipop ( ロリポップ ) 6.0 M arshmallow (マシュマロ) 7.0, 7.1 N ougat (ヌガー) 8.0, 8.1 O reo (オレオ) 9.0 P ie (パイ) 当日 誕生祭の当日、オフィスフロアに突然バースデーソングが流れてイベントが始まります。まずはバースデーケーキの代わりの Android スイーツの登場です。ろうそくは Cupcake ( Android 1.5) にさして消してもらいました! 本人も驚きを隠せない様子 ずらりと並んだ Android スイーツ そして、さらなるサプライズ。 スペシャ ルゲストとしてドロイド君(をかぶったメンバー)が登場!ドロイド君になりきってプレゼントを渡しました。 ドロイド君は踊りが得意 だよ!というフリで華麗?なダンスも披露してくれましたよ。 I am Droid. 最後に本人から一言もらって誕生祭は終了です。この誕生祭を本当に喜んでくれて、来年からの正式入社に向けての意気込みを熱く語ってくれました!お祝いしたメンバーも、本人の笑顔を見てとても満足です。 さいごに 今回のエンジニアブログでは、普段はあまりお伝えできていないプロダクト部のハートフルなところをお伝えしましたが、いかがでしたでしょうか。プロダクト部では技術やプロダクトはもちろん、チームや仲間ひとりひとりに真剣に向き合いながら開発を進めています。弊社ではこのチームの中で一緒に働いてくれるエンジニアを募集しています。ご興味のある方はぜひスタメンのエンジニ アサイ ト stmn, inc. Engineers をご覧ください。
スタメンでエンジニアをしている 田中 です。 皆さんはJay Fieldsの著「 リファクタリング : Ruby エディション」という本をご存じでしょうか? リファクタリング における有名な本として、Martin Fowlerの著「 リファクタリング 」という本はご存じの方が多いかと思います。 こちらは当時広く知られていた Java (初版), JavaScript (第二版)でサンプルコードが書かれていました。 「 リファクタリング : Ruby エディション」は原著である「 リファクタリング 」を Ruby に対応させたもので、 Ruby の特徴を活かした リファクタリング の方法が載っており、一度は読んでみたいと思っていました。しかしながら、こちらの本は現在絶版のため入手することが難しいです。 今回、縁があってこちらの本をお借りする機会がありましたので、その内容についてご紹介します。 リファクタリング をする上で大切なこと いくつか良いなと思った文章があったので引用の形でご紹介します。 リファクタリング について リファクタリング とは、コードの外からふるまいを変えずに、内部構造を改良するようにして、ソフトウェアシステムを変えていくプロセスである。   コンピュータが理解できるコードなら誰でも書ける。優れた プログラマ が書くのは、人間が理解できるコードだ。   あなたが リファクタリング をしているのは、真実や美を追求するためではない。世界をわかりやすくして、ばたばたと揺れ動いているプログラムの支配権を再び握るために努力しているのである。 テストについて リファクタリング を始める前に、しっかりとしたテストが必要だ。   リファクタリング ではテストが命綱になる。 リファクタリング が成功するかどうかはよいテストが用意できているかどうかによって左右される。 パフォーマンスとの兼ね合い リファクタリング をしているときはわかりやすくすることに集中すべきで、パフォーマンスをあげることはその後で別の仕事として行うのが正しい方法である。 大切なことは ふるまいを変えない ふるまいを保証するためにテストを書く パフォーマンスはまた別のタスクとして考える 私自身は リファクタリング とパフォーマンスの役割の違いについては特に意識しないといけないと思いました。 リファクタリング 時にパフォーマンスも併せて考えてしまっていましたが、そもそもの目的が異なるので書くべきコードは違うものです。まずは リファクタリング によって分かりやすくした上で必要に応じてパフォーマンスチューニングといった流れを意識していきたいです。 具体的な手法 数多くの方法が紹介されていますが、ここでは3つに絞って紹介します。 サンドイッチメソッドの抽出 ほぼ同じ内容のコードのメソッドが2つあり、それらの違いがメソッドのちょうど中頃のみの場合に、重複部分を抽出してブロック付きのメソッドにする。 サンプル 変更前 def charge (amount, credit_card_number) begin connection = CreditCardServer .connect(...) connection.send(amount, credit_card_number) rescue IOError => e Logger .log " Could not submit order #{ @order_number } to the server: #{ e }" return nil ensure connection.close end end 変更後 def charge (amount, credit_card_number) connect do | connection | connection.send(amount, credit_card_number) end end def connect begin connection = CreditCardServer .connect(...) yield connection rescue IOError => e Logger .log " Could not submit order #{ @order_number } to the server: #{ e }" return nil ensure connection.close end end 前処理と後処理が必要なメソッドで具体的な処理の中身を変えたい場合に活用できそうだと感じました。ブロックを利用した書き方が Ruby っぽく、またこの書き方が私自身あまり使いこなせていないと思ったのでご紹介しました。 条件分岐の組み換え Ruby では nil ガードという書き方があるので、 三項演算子 で書かずに Ruby らしい書き方をしようということでした。この他にも Ruby で提供されている記法に則ることでよりシンプルに書けそうだと思いました。 サンプル 変更前 paraneters = params ? params : [] 変更後 parameters = params || [] 他の言語を経験していると、つい Ruby らしさを忘れた書き方をしてしまいがちなので、気をつけないといけないと思いました。 条件分岐のネストからガード節へ 正常な実行経路が分かりにくい条件分岐を持つメソッドがある場合に、すべての特殊条件をガード節で処理する。 サンプル 変更前 def pay_amount if @dead result = dead_amount else if @separated result = separated_amount else if @retired result = retired_amount else result = normal_amount end end end return result; end 変更後 def pay_amount return dead_amount if @dead return separated_amount if @separated return retired_amount if @retired normal_amount end 早期returnと呼ばれている方法ですが、全てのケースにて適用して良いというわけではありません。 たとえば、条件分岐があるときに両方とも正常なふるまいである場合はガード節へ移動してはいけません。 あくまで、異常系(特殊条件)は早期returnしようという考えのもとで上記のような リファクタリング を行う必要があるのだと思いました。 おわりに リファクタリング と Ruby における具体的な方法について、「 リファクタリング : Ruby エディション」をもとにご紹介しました。 Ruby らしさを活かした書き方が多くあり参考になりました。今回いくつかの方法をご紹介しましたが、その他にも様々な方法が載っています。しかし、今の私にすべての方法が必要かと言われるとそうとは言い切れません。扱うソフトウェアの規模の大きさや状態によって、何が必要かは変わってくるものだと思います。必要になる機会は今後必ずあると思うので、そのときに再度手にとって読み返したいと思います。 ただ、冒頭にもお伝えしたとおり、こちらの本は現在絶版のため入手することがとても難しいです。 復刊ドットコム というサイトにてリク エス トをすると、リク エス ト数によっては復刊されることもあるそうなので、ご興味ある方はリク エス トしていただけると幸いです。( こちら からどうぞ) 本記事を執筆中に復刊されました!!!元々の販売価格よりも高めではありますが、これまでなかなか手に入らなかったことを考えると新品でこの価格はかなりお買い得に感じます!!(私は注文しました!!) ご興味ある方は こちら からどうぞ!!! 最後になりますが、株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひ エンジニア採用サイト をご覧ください。 Photo by João Silas on Unsplash
明けましておめでとうございます。エンジニアのミツモトです。 本年もよろしくお願いします。 ちょうど1年前、 Webアプリケーションエンジニアとしての1年目を振り返る を投稿しました。 あれから1年経過し、スタメンでの自身の役割に変化があったので、今回はその事をお伝えします。また、プライベートでは個人開発が進んだ1年だったので、そのことについても触れたいと思います。 目次 フロントエンドを担当 プロダクト・マネジメントを担当 個人開発 おわりに フロントエンドを担当 1年前はサーバーサイドエンジニアとして、 Ruby on Rails による開発を行っていました。体制の変更により、昨年2月からフロントエンドエンジニアとして React による開発を行い、スタメンで提供している TUNAG では、主にタイムラインと呼ばれる部分を担当しています。 転身した当時、フロントエンドエンジニアは自分1人でした。そこから少しずつ人数が増え、フロントエンドチームができ、現在は3人で開発しています。ちなみにフロントエンドチーム以外でも React による開発を行っており、社内で React を書けるエンジニアはこの1年で増えました。 初めは技術的な相談をできる人が少なく、 ソースコード を理解し、機能を追加するのに苦労しました。今は相談できる相手が社内にいるので、本当にありがたいです。「このコードは読みやすいか?」「 ディレクト リ構成をどうするか?」など、議論しながら日々開発をしています。 技術的な内容は、以前 Railsエンジニアがフロントエンド開発に入門してみた でもご紹介しましたが、TUNAG は元々 JavaScript × クラス コンポーネント でコーディングしていました。半年くらい前から TypeScript × 関数 コンポーネント で開発するようになり、状態管理は、規模の小さなものは React Hooks の useState、大きいものは Redux で行っています。 最近は、新規プロジェクトで Webpack による環境構築から React ・ Redux によるコーディングまで行っています。業務で SPA をゼロから構築するのは初めてですが、 package の選定・プロジェクト固有の仕様をどう実現するか?を考えながら実装するのは、とても面白いです。 プロダクト・マネジメントを担当 エンジニアリングを行う一方で、 TUNAG における新機能のプロダクト・マネジメントを担当する機会がありました。担当したのは、タイムラインの表示を最適化するため、関連した投稿をまとめるグループ機能です。 具体的な内容は割愛しますが、機能の対象・課題を整理して目的を定め、要件を定義し、リリース後にどのような効果があったか振り返る。という一連の流れを行いました。担当して感じたのは、要件を定義し、 UI に落とし込むことの難しさです。 エンジニアリングだと、基本的に明確なゴールがあり、それに向かい実装していきます。もちろん技術選定や細かな仕様で迷うことはありますが、最終的なアウトプットははっきりしています。プロダクト・マネジメントは、そのゴールをどこに置くか?を決めるものになります。最低限必要なものは何か考え、要件定義し、 UI として表現するのは、答えが1つではないため難しかったです。 また、実際にやってみると「折角この機能を作るなら、これもあった方がいいのでは?」という想像が広がります。それが過剰になると目的がズレます。すると、その後のデザイン・実装も大きくブレて、場合によっては作ったものが無駄になってしまうこともあります。常に「そもそも何がしたいか?」を振り返るようにしていました。 プロダクト・マネジメントに関して、以下の本がとても参考になりました。 リーン・スタートアップ ムダのない起業プロセスでイノベーションを生みだす 仮説を立て、それに基づく最小限の製品(機能)を作り、検証して次の施策を立てる。そのサイクルを早く回す。プロジェクトを進める上で、重要なことがたくさん書かれており、オススメです。 個人開発 プライベートでは、個人開発が進んだ1年でした。 最近はデスクトップ向けのToDoアプリを開発しています。 個人開発のアプリは、触れたことのない技術を試す最高の場所です。 今回のアプリでも、 * 認証: Firebase Authentication * 画像管理: Cloudinary * API : GraphQL など、やってみたかったことを試せました。 こういった技術を試すことで、ドキュメントやライブラリの ソースコード を読む機会が増えたのも良かったです。不明な点があれば、まず一次情報を見る習慣が付きました。より多くのユーザーに使ってもらえるよう、引き続き開発を進めていきます。 おわりに 最後までご覧いただきありがとうございました。 エンジニアがどんな風に働いているかお伝えできればと思い、自分の振り返りも兼ねて今回の記事を書きました。 スタメンでは新しいことに挑戦できる機会がたくさんあります。興味のある方は是非 こちら をご覧ください。
こんにちは。スタメンでバックエンドエンジニアをしております、 永井 です。 入社して半年ほど経ちますが、任される業務の幅や深さが広がっていき、毎日わくわくしながら働いています。 この前、 Ruby で生成したファイルを直接、 Ruby のGem 「 google -drive- ruby 」を使用して、社内で使っている Google Drive にフォルダ指定してアップロード(ダウンロード)する方法を勉強しました。 今回はその詳しい内容と方法を紹介したいと思います。 目次 「 google -drive- ruby 」とは? Google Drive の設定 「 google -drive- ruby 」でアップロードする おわりに 「 google -drive- ruby 」とは? 「 google -drive- ruby 」とは、 Google Drive にあるファイルや スプレッドシート に対して、書き込みや読み込みを行ったり、ファイルをアップロードしたりすることができる、 Ruby のGemです。 公式ドキュメントは こちら です。 Google Drive の設定 「 google -drive- ruby 」を使って、 Google Drive にファイルをアップロードするには、アップロード先の Google Drive から認証情報を取得しなければいけません。 ログインをするための認証情報には、「OAuth クライアント ID」と「サービス アカウント キー」の2種類がありますが、前者の「OAuth クライアント ID」を使用した認証方法は、手動で認証ボタンをクリックする必要があります。そのため、capybaraやwheneverを使った自動化処理、定期処理には向きません。今回は Ruby の方で自動化処理をしたかったため、後者の「サービス アカウント キー」を使用して、 Google Drive へログインします。 ちなみにサービスアカウントとは、人間ではない仮想的なアカウントであり、アプリケーションなどのシステムが使用します。詳しくは 公式ドキュメント を御覧ください。 それでは、まずサービスアカウントを作成するところから始めます。 1.   GCP(Google Cloud Platform) にログインします。 2. 左タブの「 API とサービス」から「認証情報」のページに飛びます。 3. 「認証情報を作成」というプルダウンから、「サービス アカウント キー」を選んで、認証情報をダウンロードします。   アップロードする前の準備として、認証情報で得た JSON ファイル内の private_email というメールアドレスを、アップロードしたいフォルダの共有に加えて、サービスアカウントに権限を付与する必要があります。 1.  アップロード先のフォルダから共有を選択 2. 先程のメールアドレスを入力 これで、アップロード先を指定することができます。   「 google -drive- ruby 」でアップロードする まず、「 google -drive- ruby 」をインストールします。 Gemfileに以下を記述。 gem ' google_drive ' bundle installを実行。 $ bundle install --path vendor/bundle これでGemがインストールされました。 ここから、 Ruby でアップロードをする処理に移っていきたいと思います。   private_key = OpenSSL :: PKey :: RSA .new( Rails .application.secrets.google_drive_private_key) client = Signet :: OAuth2 :: Client .new( token_credential_uri : Rails .application.secrets.google_drive_token_uri, audience : Rails .application.secrets.google_drive_token_uri, scope : %w( https://www.googleapis.com/auth/drive https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/ ) , issuer : Rails .application.secrets.google_drive_client_email, signing_key : private_key ) client.fetch_access_token! GoogleDrive .login_with_oauth(client.access_token) ここでは、先程ダウンロードした、認証情報が含まれるファイル読み込んで、ログインするまでの処理を行っています。 client.fetch_ access _token! では Google サーバーから、アクセス トーク ンを取得してきます。そのアクセス トーク ンを login_with_auth メソッドの引数に渡して、 Google Drive にログインしています。 次に、フォルダを指定してファイルをアップロードしていきたいと思います。   # Google Driveにログイン session = GoogleDrive .login_with_oauth(client.access_token) # 適当にファイルを作成 file = File .open( " test.txt " , " w+ " ) # アップロードしたいフォルダを指定 folder = session.file_by_title( " sample_folder " ) # ファイルを指定して、sample_forlerにアップロード folder.upload_from_file(file, " hoge.pdf " , convert : false ) ログインした後、まずアップロードする先のフォルダを file_by_title でフォルダ名を指定して探します。もし指定したフォルダ名が存在しないければ、 nil が返ってきます。 そのフォルダに対して、 upload_from_file メソッドでアップロードを行います。第1引数にアップロードしたいファイル、第2引数に自由なタイトルを指定します。 ちなみに、第3引数に convert: false を指定すると、 Google Drive へアップロードした後に、 Google Drive の方でフォーマットを変更されずに保存されます。 アップロードが完了して、 Google Drive の指定のフォルダを見てみると、ちゃんとアップロードされていますね。 ダウンロードも同様に行うことができます。 # Google Driveにログイン session = GoogleDrive .login_with_oauth(client.access_token) file = session.file_by_title( " test.txt " ) # 引数にダウンロード先のパスを指定 file.download_to_file(path) file = session.file_by_title("test.txt") でダウンロードしたいファイル名を指定します。そして、 file.download_to_file(path) でダウンロード処理を実行します。 おわりに Ruby のgemである「 google -drive- ruby 」を使えば、簡単に指定の Google Drive フォルダにアップロードができました。今回は Google Drive API の知識を深めることができましたが、今後は、その他のG Suiteや、 GCP に関する知識も付けていきたいと思います。 最後に、株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひ エンジニア採用サイト をご覧ください。 CPに関する知識も付けていきたいと思います。 最後に、株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひ エンジニア採用サイト をご覧ください。
はじめに こんにちは!スタメンで内定者 インターン をしている梅村です。 内定をいただいてから今まで、約半年間 インターン を行ってきました。 今回は インターン の振り返りを記述しようと思います。 自己紹介 自分は現在、愛知県の大学に通う 修士 2年生です。大学では最適化を専攻していて、その中でも ポートフォリオ 最適化問題 に取り組んでいます。 今年の4月に20卒エンジニアとして内定をいただき、5月からプロダクト部で内定者 インターン をしています。 自分以外のスタメン新卒エンジニアは、 インターン から内定の流れでジョインしている人が多いですが、自分は内定から内定者 インターン の流れでスタメンにジョインしました。 大学の講義や研究でプログラミングは経験してきたものの、スタメンで インターン を始める前まで Rails に触れたことがありませんでした。しかし、半年間の インターン で、 Rails を用いた TUNAG の新機能開発・機能改善を行えるまで成長しました。 以下では、普段の1日のスケジュール、どのような業務を行ってきたかを記述していきます。 1日のスケジュール 9:15 - 出社 9:30〜9:45 - プロダクト部、所属チームで朝会 9:45〜12:30 - 開発 12:30〜13:30 - 昼休憩 13:30〜15:30 - 開発 15:30〜16:00 - プロジェクトミーティング 16:00〜18:00 - 開発 18:00〜18:30 - 日報作成 18:30 - 退社 以上が1日のスケジュールです。 朝会はプロダクト部全体で行った後に、チーム単位でも行います。機能のリリースがある場合は全体で共有します。チーム単位の朝会では、チーム一人ひとりのタスク共有・懸念事項の共有を行います。 朝会が終わった後は開発業務に取り掛かります。開発環境として会社から MacBook Pro の15インチ、30インチの4Kディスプレイ、キーボード、マウスが支給されます。自分は肩こり軽減のためにデュアルキーボードで開発しています。 昼休憩の過ごし方は人それぞれです。自分は、昼はよくコンビニへ行きますが、飲食店へ行ったり、弁当を持ってきている人もいます。デスクで作業しながら食事をしたり、共有スペースで会話しながら食事、家が近い人は家で食事している人もいます。 昼休憩が終わった後は、引き続き開発を行います。日々プログラミングばかりしているわけではなく、コードレビューやドキュメントの作成も行います。スタメンのプロダクト部では技術力だけでなく、読む力や ドキュメンテーション 力も磨けます。 終業時間近くになると日報を書き始めます。日報では、タスクの進行状況、今後の予定などから、最近学んだこと、日頃感じていることを記述します。 このような感じで1日が終わります。終業後はチームメンバーと勉強会をしたり、スタメンのオフィスを貸し出して もくもく会 を行うこともあります。 以下は、勉強会の写真です。 インターン ではありながらも、社員と同じ業務、勉強できる環境が揃っています。 これまでの開発内容 自分はWebアプリケーションチームに属していて、主にTUNAGの新機能開発、機能改善を行っています。Webアプリケーションチームでは、バックエンドは Rails 、フロントエンドはReactを用いて開発しています。自分は今までの開発業務では Rails しか触っていませんが、今後はReactも触る予定です。 インターン を始めて最初の業務は、プライバシーポリシーのリンク先のURLを変更する作業でした。簡単な変更でしたが、初めてのリリースだったので、とても緊張したのを覚えています。 しばらくしてある程度 Rails が触れるようになると、TUNAGの少し複雑な機能の修正を任されるようになりました。TUNAGに関してのお知らせを表示する際に、利用している機能ごとに出し分け、デ バイス ごとに出し分けできるようにする、という修正です。 それまでの業務は、ピンポイントで修正すれば済むようなものを行っていました。ですが、この修正部分は色々な箇所の影響を受けていた・与えていたので、そもそもどこを修正すればいいのか理解するまでに時間がかかりました。理解してからも、メソッドの書き方、画面の表示方法など、新しいことの連続で苦戦しましたが、とても良い勉強になりました。 その後は、新機能を2つ開発しました。新機能開発では、設計からモデル作成、コントローラー作成、ビュー作成を一通り行い、学んできたことの集大成となるような業務でした。新機能開発を通して、 マイルストーン の作成の難しさを実感しました。 マイルストーン 作成では、自分の持っているスキルと照らし合わせながら、何週間・何ヶ月先を考えます。自分は、 マイルストーン 作成時に細部まで考えきれておらず、途中で開発の流れの変更、最終的なリリース予定日をズラすことになりました。これからは意識的に前倒して開発していくことを心がけていきます。 インターン を通して学んだこと 半年間の インターン を通して、自分の意見を持つ重要さを学びました。スタメンは自社開発企業です。自分たちでサービスのロードマップを考え、開発していきます。より良いプロダクトを作っていくために、プロジェクトの責任者として意見を持ち、時には上司や他部署の人とも意見をぶつけ合わなければなりません。スタメンのプロダクト部では、ただ言われた通り開発するだけでなく、良いプロダクトを作るためにはどうすればいいか考えられるエンジニアを必要としています。 そこで自分はどうだったかというと、プロジェクトの責任者として意見を持てておらず、オープンな質問ばかりしていました。自分が意思決定をする場面でオープンな質問をしてしまい、何も決まらない。結局上司に聞いて遅れが発生する、ということが多々ありました。新機能開発ではこの問題が顕著に表れていて、成長した反面、課題も出てきたタスクとなりました。 ただ、 インターン の段階で自分の課題に気づけたのはとても幸運です。正式に入社するまでに、自分の意見を持つことを意識しながら開発を進めていきます。 おわりに スタメンでは若手に多くのチャンスが降ってきます。また、周りには優秀なエンジニアが多く、切磋琢磨できる環境です。自分は、 インターン の段階から多くを任せていただき、成長してきました。これから正式に入社して、良いプロダクトを作るために全力を注げる、成長していけると考えると、ワクワクが止まりません。 最後に、株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひ エンジニアサイト をご覧ください。
スタメンのデザイナーの @kiyoshifuwa です。 先月、 Designship に参加してきました! セッション内容についての記事はすでに登壇者や参加者の方が出されていますので、本記事では特に印象に残った3つの学びについてお伝えします。 1.「あったらいいな」はやらない popIn株式会社 北村 崇さん「世界初を支えるデザイナーが考えること」のお話の中で、「あったらいいな」はやらない という話がとても印象に残っています。 開発を進めていく中で、あれもこれもやりたいというア イデア が色々出てくるのはよくあることです。しかし、安易に「あったらいいな」をやり始めてしまうと、「じゃあこれもやろう」「どこまでやるのか」などの議論が始まり収集が付かなくなります。 たくさんの仕事を限られた時間・リソースの中で順序よく進めるためには、「やるべきこと」を優先順位付けして進めていく必要があります。 これまでは、なにを基準に「やる」「やらない」を決めてよいのか自分の中で判断基準がなく、その都度プロジェクトマネージャーに判断を任せてしまっていました。 今回のセッションを受け、「やるべきこと」はやる、「あったらいいな」はやらないという明確な判断の軸が自分の中で生まれました。 また、「派生でできたもの」や「おまけ機能」はユーザーに取って必ずしも「親切」ではなく、かえって「不慣れ」を生み出し「不安」にさせてしまうことがあることも知りました。 それからは、「あったらいいな」が出てきたら、以下のふるいにかけて「やる」「やらない」の判断をするようにしました。 それはユーザーに求められていることなのか やらないと機能しないよ うな重 大な要素なのか 私たちの意志を込めることにおいて重要な役割があるのか 優先度が高い他のものを後回しにしてまで今やる必要があるのか   「開発途中で出てきたア イデア は全部無視!」ということではなくて、 やるべきだと判断したことは 「あったらいいな」から「やるべきこと」に明確に格上げする必要がある ということです。 自分の中で判断の軸がしっかり定まったことは、とても大きな収穫でした。 👇このセッションで学びました “世界初”を支えるデザイナーが考えること popIn株式会社 北村 崇さん スライドは こちら   2.考え方を考えてから考える   グロービス経営大学院 の論理力向上ワークショップに参加し、 「洗濯機の販売利益を上げるための施策を5分以内にたくさんリストアップする」という演習をしました。 私が参加したグループでは、とにかく急いでたくさんのア イデア を出さなければ!と、みんなで闇雲に思いついたア イデア を連ねていきました。その結果、途中でア イデア 出しが止まってしまいました。 また、包含関係にあるア イデア を並列に扱うなどしていたので、後から情報を整理して発表をすることが大変になってしまいました。 この演習で想定している最終的なゴールは、「ア イデア をたくさん出す」ことではなくその先の「施策を提案し、洗濯機の販売利益を上げる」ことですが、そこまで考えが至っていませんでした。 一方、ア イデア を効率的にたくさん出していたグループは この洗濯機が抱えている課題を想定する 「販売利益」とはなにを指すのかの確認 など、 前提 からし っかりメンバーで認識を合わせ、効率よく考えて ア イデア 出しを進めていました。順序立てて考えられているので、説明もとてもわかりやすかったです。 なにも考えず闇雲に進めていくよりも、課題や前提をしっかりと認識し、「考え方を考えてから考え始める」方が 無駄がなく効率よく進められる 主観や経験によって偏らない 説明がしやすい などのメリットがあることをこの演習で学びました。 このような内容は座って話を聞いているだけではイメージが湧かず「ふーん」で終わってしまいそうですが、失敗を経験したことで自分の中で深く印象に残ったので、実践形式で学べてとても良かったと思います。 👇このワークショップで学びました 【少人数限定】デザイナーのための論理力向上ワークショップ by グロービス 詳細は こちら   3.「優しいデザイン」=「使いやすいデザイン」だけじゃない クックパッド 株式会社宇野 雄さん「月間5,400万人を支えるユーザ体験への想いとその現実」は、「毎日の料理を楽しみにする」というミッションを実現するために、現実に対して「優しいデザイン」と「おせっかいなデザイン」という概念を用いているというお話でした。 「優しいデザイン」の例のひとつとして、「今月は10回も料理したよ」を「今まで10回も料理したよ」と表現するというお話がありました。 前者の「今月は10回も料理したよ」は、きちんとできたことを可視化して肯定しているのはとてもよいのですが、 「21回料理しなかった」ことも可視化 されてしまいます。 なので、あえて「今まで10回も料理した」という積み上げだけを伝えています。 事実は変わりませんが、「料理をしたこと」のみを伝えるようにしています。 「ユーザーにとって優しいデザインを作ること」が大切だということはもちろん理解しています。ただ、私の中には優しくする手段が「ボタンを押しやすくする」、「イラストで説明する」など、使いやすく・わかりやすくすることしかなかったので、ことばの表現や図の表現を変えるという手段は 目から鱗 でした。 それぞれのサービスのユーザーにとって優しいことは何なのか を考え、ことばや図を含め最適な表現をしなければならないと思ったセッションでした。 👇このセッションで学びました 月間5,400万人を支えるユーザ体験への想いとその現実 クックパッド 株式会社宇野 雄さん noteは こちら   さいごに 2日間 朝から夕方までインプット漬けで大満足のDesignship2019でした。 凝り固まっていた考え方が柔軟になり、一歩レベルアップした実感があります。 気になった項目があれば、 こちら で映像が配信されていますので ぜひご覧になってください! 株式会社スタメンでは一緒に働く仲間を募集しています。 こちら からぜひお気軽にお話を聞きに来てください!
はじめに こんにちは。スタメンでバックエンドの開発をしております、河井です。 今回の記事では、毎月開催されている社内勉強会について、運営方法を変えてみたこととその振り返りについて書いてみます。 背景 スタメンでは、毎月業務時間内に社内勉強会を開催しています。 今年の6月に運用を変えてみたのですが、それまでは社内勉強会の主催者は明確に決まっておらず、都度だれかが手を上げて主催して発表者を集める、という形でやっていました。 人数が少ないときはこれでも良かったものの、だんだんと人が増えてくるにつれて、発表者が偏ってきたり、会の時間が長くなりすぎたりと、誰か主催者を決めて運用ルールを決めないともたないな、と感じてきました。 というわけで、勉強会をより参加する価値のあるものにするため、社内勉強会の運用を考え直すことにしました。 勉強会で大切にしたいこと 今後の運用を考えるとき大事にしたことは以下の3点です。 業務での担当領域以外の情報を共有 エンジニアチーム全体でのコミュニケーション 純粋に技術を楽しむ 業務時間内で行うので、しっかりとやる価値のあるものにする必要があります。とはいえルールで縛りすぎて形だけになってしまうのは本末転倒なので、楽しく発表したり聞いたりできる場にしたいと思いました。 どう変えたか 最初に結論を書くと、次のようなルールで運用することにしました。 Webフロントエンド、ネイティブアプリ、Rails アプリケーション、バックエンドの各チーム※から代表者1人が発表 1人あたり15分 × 4人 発表ネタは必ずしも所属チームの技術に関連させる必要はない(業務で使った技術でも、趣味で勉強してみた内容でも) スライドや Qiita など何らかの形で資料にまとめること ※2019年12月現在、各チーム3、4人ほどのエンジニアが在籍 なぜチーム単位か 皆に発表する機会を与えつつ個人に負担をかけないようにするには、チームごとにして、チームの中でフォローし合えば良いのではと思った 個人単位で順番に回すとすると、業務が忙しい時期に発表が被るなどすると勉強会が負担になる 順番ではなく自由に発表するようにすると、発表する人や回ごとで発表者の人数が偏る 発表担当をチームごとに割り振ることで、話題の偏りをある程度避けられる 次回の発表担当を決めるついでに発表ネタの話をチームメンバーに相談できる といったように、ルールを設けつつも、自由を残す余地が生まれると考えたからです。 半年間運用してみて 参加したメンバーにアンケートを取ったところ、次のような声をもらっています。 良かったところ チームごとで決めることで、発表しない人も含めて全員が当事者になれるので、それが良い文化になっていると思う チーム内での情報共有は普段からしているから、勉強会がチームを超えた関わりの機会になっている 改善できそうなところ 技術的な解説をしっかりしようとすると15分では短いと感じる 発表に対するフィードバックがほしい などなど、良い点についてはチーム制ならではだと思うので当初の狙い通りの結果になったのではないかと思います。 改善点の1つ目については僕もなんとなく感じていたことで、今は月一回なので、隔週にして LT 会と長く話せる場をそれぞれ設けるのもアリかなーと考えています。 発表内容をいくつか 発表で出てきた内容をいくつかピックアップしてみます。 iOS と Android の User Interface の違いについて Gatsby + Netlify でブログを立ち上げるハンズオン 自作キーボード入門 Firestoreとセキュリティルール React Hooks ActiveRecord を読む ReactiveX入門 Maker Faire Tokyo 2019 参加レポート 業務に関連した話から、個人でやってみた技術的な趣味の話まで色々な領域の話が出てきています! 先日もこんな感じで盛り上がりました! 最後に 株式会社スタメンでは、一緒に開発する仲間を探しています。興味のある方はぜひ エンジニアサイト をご覧ください!
スタメンでエンジニアをしている 田中 です。 普段はRailsエンジニアとしてTUNAGの機能改善を行なっていますが、以前から挑戦したかったフロントエンド開発の機会をいただけたので、今回はフロントエンド開発に入門してみた感想を記述します。 フロントエンド開発環境 はじめに、スタメンのフロントエンド開発環境について説明します。 スタメンのエンジニアが作っている『TUNAG』の技術的な解説 にも一部記載がありますが、本記事ではフロントエンドにフォーカスを当てた内容で説明します。 使用言語 TypeScript: 3.5.3 主なライブラリ React: 16.8.6 React-Router: 5.0.1 Redux: 4.0.4 Redux-Saga: 1.0.5 styled-components: 4.3.2 ESLint: 6.2.1 Jest: 24.9.0 Enzyme: 3.10.0 元々はJavaScriptで記述していたこともあり、TUNAG全体ではJavaScriptのコードが多いですが、新規に作成する機能に関してはTypeScriptで実装しています。また今後はJavaScriptで書かれたコードをTypeScriptで書き換えることを計画しています。 入門してみた感想 React Hooksでスッキリ書ける React Hooksとは フック (hook) は React 16.8 で追加された新機能です。state などの React の機能を、クラスを書かずに使えるようになります 引用: フックの導入 – React 数ヶ月前からスタメンでも利用できるようになりました!(導入までの苦労話は こちら から) これまでクラスコンポーネントのみで利用できたstateやライフサイクルメソッドが、React Hooksの登場により関数コンポーネントでも書けるようになります。 コード例として、全く同じ挙動をするコードをクラスコンポーネントで書いた場合と関数コンポーネントで書いた場合を並べてみました。 基本 クラスコンポーネント class Welcome extends React.Component { render () { return <h1 > Hello , { this. props . name } < / h1>; } } 関数コンポーネント const Welcome = ( props ) => { return <h1 > Hello , { props . name } < / h1>; } 引用: コンポーネントと props – React state クラスコンポーネント class Example extends React.Component { constructor ( props ) { super ( props ) ; this. state = { count : 0 } ; } render () { return ( <div > <p > You clicked { this. state . count } times < / p> <button onClick={ () => this.setState ( { count: this.state.count + 1 } ) }> Click me < / button > < / div> ) ; } } 関数コンポーネント import React , { useState } from 'react' ; const Example = () => { // Declare a new state variable, which we'll call "count" const [ count , setCount ] = useState ( 0 ) ; return ( <div > <p > You clicked { count } times < / p> <button onClick={ () => setCount ( count + 1 ) }> Click me < / button > < / div> ) ; } 引用: ステートフックの利用法 – React ライフサイクルメソッド クラスコンポーネント class Example extends React.Component { constructor ( props ) { super ( props ) ; this. state = { count : 0 } ; } componentDidMount () { document . title = `You clicked ${ this. state . count } times` ; } componentDidUpdate () { document . title = `You clicked ${ this. state . count } times` ; } render () { return ( <div > <p > You clicked { this. state . count } times < / p> <button onClick={ () => this.setState ( { count: this.state.count + 1 } ) }> Click me < / button > < / div> ) ; } } 関数コンポーネント import React , { useState , useEffect } from 'react' ; const Example = () => { const [ count , setCount ] = useState ( 0 ) ; // Similar to componentDidMount and componentDidUpdate: useEffect (() => { // Update the document title using the browser API document . title = `You clicked ${ count } times` ; }) ; return ( <div > <p > You clicked { count } times < / p> <button onClick={ () => setCount ( count + 1 ) }> Click me < / button > < / div> ) ; } 引用: 副作用フックの利用法 – React ご覧いただいた通りですが、どの項目についても関数コンポーネントの方がスッキリと記述できます。React Hooksの話を聞いた当初は、「そんなに大きく変わるものなのかな・・・」と思っていましたが、実際に手を動かしてみるとシンプルで直感的に書けて良いな!ということがよく分かりました。 styled-componentsがとても良い styled-components とはコードの中にstyleを記述するCSS in JSのライブラリの1つです。 下記のようにコードの中にスタイルを記述することが出来るので、具体的にどこにスタイルが適用されているか分かりやすいです。 import React from 'react' ; import styled from 'styled-components' ; const Title = styled . h1 ` font-size: 1.5em; text-align: center; ` ; const Wrapper = styled . section ` padding: 4em; ` ; <Wrapper > <Title > Hello World , this is my first styled component ! < / Title> < / Wrapper > また、コンポーネントの継承により、共通のスタイルを適用できます。 const Button = styled . button ` padding: 12px; border-radius: 4px; ` ; const OKButton = styled ( Button ) ` backgroud-color: blue; ` ; const NGButton = styled ( Button ) ` backgroud-color: red; ` ; これまでスタイルを設定しても上手く適用できない場合、 idやclassの指定が間違っている BEMの記述が間違っている CSSの記述が間違っている のようなエラーになりうる要因がいくつかありましたが、styled-componentsでは適用したい箇所に直接指定できるため、CSSの記述に注力するだけで良くなりました。また、コンポーネント単位で設定できるため、影響範囲が限定的となり、スタイルの変更がしやすくなりました。 CSSに対して「上手く適用できない」「修正時の影響範囲が分かりにくい」といった苦手意識を持っていましたが、styled-componentsによってCSSと仲良くなれそうな気がします! ディレクトリ構成に悩む Railsでは rails new コマンドで基本的なディレクトリ構成が出来るため、生成されたとおりにファイルを配置すればよいのですが、Reactにおけるディレクトリ構成は開発者が設計する必要があります。そのため、世の中にはReduxの役割ごとに構成したり、Atomic Designに則った形で構成したりと様々なパターンが存在しています。 大雑把な説明となりますが、本記事を記述している時点における直近の開発では下記のような構成にしています。 Reduxの役割ごとにディレクトリを作成 Componentsディレクトリを作成し、その配下にcommonや各機能を入れる 過去の記事 とは異なる構成となっているので、その時々のベストな構成をこれからも探す必要があるのだろうなと思いました。 おわりに 初めてのフロントエンド開発はReact Hooksやstyled-components、そしてTypeScriptによる静的型付けによって効率的に開発を進めることが出来ました。言語の違いのみならず、様々な点でRailsとは大きく違いましたが、その違いを楽しみつつ開発することが出来ました。 また今回の開発をきっかけにフロントエンド開発にも携わるようになり、自身の技術領域が広がりました。こうした挑戦の機会がスタメンでは数多くあるため、成長できる良い環境だと改めて思いました。 最後に、株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひ エンジニア採用サイト をご覧ください。
スタメン エンジニアの松谷( @uuushiro )です。 2019年12月01日(日)〜12月06日(金)に AWS 最大のカンファレンス AWS re:invent 2019 がラスベガスで開催されました。 AWS Summit Tokyo 2019 の Startup Architecture Of The Year で スタメンがグランプリを獲得したとき の副賞として re:invent のペアチケットを頂いたので、CTOの小林と2人で初参加してきました! 目的 re:inventの予定を組む前に、 AWS re:Invent 参加7回目のエンジニアがおくる re:Invent 2019 おすすめの過ごし方 というブログを拝見し、「現地でしか得られないもの」にこだわって過ごそうと決めていました。現地でしか得られないものは人それぞれですが、僕は keynote , GameDay, SecurityJam は絶対参加しようと意気込んで行きました。それぞれについて簡単に振り返りたいと思います。 Keynote AWS CEO Andy Jassy の3時間にわたる熱演は圧巻でした。今年も多くのサービスが発表され、ひとつ発表があるたびに会場の熱気を感じました。特に、SageMaker など 機械学習 に関するリリースが多かったことが印象に残っていて、サービスのマネージド化が進み、 コモディティ化 していく勢いの速さを感じました。 Keynote だけでなく、GameDayに参加した海外のエンジニアと交流する中で 機械学習 を使うこと自体のハードルはかなり下がっていて、逆に利用していないだけで大きなビハインドになってしまうという危機感を感じました。 AWS が推し進める技術の コモディティ化 にちゃんとついていくことが最低限スタートラインに立つためには重要だなと感じました。 また、 Apache Cassandra がマネージドサービスとして AWS でサポートされるなど、 AWS は多くの選択肢を用意してくれます。自社の ユースケース をちゃんと理解し、それに適したサービスを選択しより良い設計にしていきたいと思います。 普段から手を動かしてサービスを触り、自分の中で引き出しを持っておき、必要な時に適切な クラウド サービスを選択できることがとても重要になると感じました。 GameDay と SecurityJam AWS GameDayとは、 AWS 上に構築したサービスの改善や、障害対応など競うコンテストです。3~4人のチーム戦で行われます。システムが安定して稼働し、サービスとして意味のある処理ができていればポイントが加点されます。 逆にサービスがダウンしていたり、適切に処理が動いていないとポイントが減点されます。今回、現地でチームを組んだので、USのエンジニア3人と僕の計4人チームを組みました。英語を半年前くらいから勉強し始めたので、どれくらい通じるだろうとドキドキしながらGameDayが始まったのですが、チームメンバーは気さくな方達で、とても楽しく会話することができました。そして役割分担、序盤のオペレーションまではなんとか英語でコミュニケーションをとりながら進めることができたのですが、障害対応のような素早いチーム連携において、今の僕の英語のレベルではかなり厳しく、日本語なら対応できるはずのスピードよりも2テンポくらい遅れてしまいました。 また、対象サービスが、 Amazon EKS・ Amazon Forecast・ AWS CodePipeline など業務で利用したことのないサービスで主に構成されていて、その場で必死にドキュメントを読みながらの対応になり、ここでもスピードを出すことができなかったです。日頃から1回は手を動かしてみることが必要だったなーと後悔していました。 AWS から「最低限これくらいは手を動かせるよね?」という暗黙のメッセージを受け取った気分でした。英語の壁だけでなく、技術的な面でも課題を感じたイベントでした。 SecurityJamは AWS 環境で起きている セキュリティインシデント に対応するコンテストです。これも3~4人のチーム戦で行うイベントですが、時間ギリギリで参加したからか、1人での参加になりました。普段セキュリティに関する業務を担当している分、早く手を動かすことができ、一時平均以上のスコアを取ることができましたが、後半失速していき微妙な結果で終わってしまいました。問題を解く中で、新しい学びになることが多かったので業務に活かしていきたいと思います! GameDay・SecurityJamともに、長丁場でとても疲れましたが、海外のエンジニアと一緒に開発をし、リアルな温度感を体感できてとても満足できました。業務の中で AWS の力がついている実感と、まだまだ実力不足だなという感覚を同時に味わうことができてとても良い機会になりました。この感覚を忘れずに成長に繋げていきたいと思います! おまけ せっかくラスベガスまで行ってきたので、グランドキャニオンに行ってきました!re:inventで、 Netflix のデプロイ回数や、 NASDAQ のデータ量など規模がスタメンとは桁違いのスケールを感じましたが、 アメリ カ大陸のスケールの大きさにもやはり驚きました。まだまだ自分やシステムの規模は小さく、これから大きくするぞ!という気持ちになりました。 最後に re:inventは「 クラウド の今」を身を持って知る良い機会でした。業務で使わないサービスに触れるいい機会でしたし、海外のエンジニアの方たちとの交流を通じて、日本だけではなくグローバルな視点で自分の位置を確認することができました。GameDayのように、色々な価値観のエンジニアの方たちと楽しく開発することはとてもワクワクするので、引き続き英語・技術ともにレベルアップして、もう一度チャレンジをしたいと思いました。現地では見れなかったセッションも Youtube や資料が公開されているみたいなので、チェックして、なるべく手を動かして理解していこうと思います! 今回、re:inventには業務として参加しており、宿泊費と交通費を会社に負担してもらいました。 スタメンでは AWS を利用する機会がたくさんあります! クラウド の進化の波に乗りながら、プロダクトを開発するエンジニア募集中です!興味がある方は Wantedly よりご連絡ください。
こんにちは。フロントエンドエンジニアの渡邉です。 先日参加した勉強会でAWS AmplifyについてのLTを聞き、興味が湧いたので、実際に使ってみました。 その詳しい内容と感じたことについて紹介します。 目次 Amplifyとは Amplifyによる公開 セットアップ 実装 Webアプリを公開 AppSyncとは AppSync導入 queries mutations おわりに Amplifyとは AWS を使用したスケーラブルなモバイルアプリおよびウェブアプリの作成、設定、実装を容易にします。Amplify はモバイルバックエンドをシームレスにプロビジョニングして管理し、バックエンドを iOS、Android、ウェブ、React Native のフロントエンドと簡単に統合するためのシンプルなフレームワークを提供します。また、Amplify は、フロントエンドとバックエンドの両方のアプリケーションリリースプロセスを自動化し、機能をより迅速に提供することができます。 引用: AWS Amplify公式 Amplifyによる公開 今回はReact + AWS Amplifyを使って認証付きの、シンプルなWEBアプリを作成、公開してみます。 事前に以下の 準備 が必要です。 - Amplify CLI のインストール - AWSアカウント設定 セットアップ まずReactのアプリケーションを作成します。 create-react-app amplify-app cd amplify-app 次にAmplifyのセットアップです。 amplify init ? Enter a name for the project amplify-app ? Enter a name for the environment prod ? Choose your default editor: Visual Studio Code // 普段使用しているeditor ? Choose the type of app that you're building javascript Please tell us about your project ? What javascript framework are you using react ? Source Directory Path: src ? Distribution Directory Path: build ? Build Command: yarn build ? Start Command: yarn start Using default provider awscloudformation For more information on AWS Profiles, see: https://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html ? Do you want to use an AWS profile? Yes ? Please choose the profile you want to use amplify-test // Amplify用のIAMアカウント 認証機能を導入します。 今回はすべての項目でデフォルト値を使用します。 amplify add auth ... amplify push amplify push コマンドで追加した機能を有効化させます。 実装 yarn add aws-amplify aws-amplify-react src/App.js を以下のように編集します。 import React from 'react' ; import Amplify from 'aws-amplify' ; import awsconfig from './aws-exports' ; import { withAuthenticator } from 'aws-amplify-react' ; Amplify . configure ( awsconfig ) ; const App = () => { return ( <div > amplify - app < / div> ) ; } export default withAuthenticator ( App, true ) ; Webアプリを公開 ここでもすべての項目でデフォルト値を使用します。 amplify add hosting ? Select the environment setup: DEV (S3 only with HTTP) ? hosting bucket name amplify-app-20191126224819-hostingbucket ? index doc for the website index.html ? error doc for the website index.html You can now publish your app using the following command: Command: amplify publish amplify publish ✔ Uploaded files successfully. Your app is published successfully http://~~~ ここにアクセス amplify publish コマンドが成功すると、中身はシンプルですが無事に 認証機能付きwebアプリ 公開完了です。 今回はホスティングを試すためにHTTPを指定しています。 上記のサイトをみる場合は普段使わないアドレス・パスワードをお使いください。 認証機能を本格的に実装する場合は必ずHTTPSを指定しましょう! これでセットアップは完了です。 これをベースに簡単なWEBアプリケーションを作っていきたいと思います。 WEBアプリのデータを保存するためにAppSyncも導入します。 AppSyncとは AWS AppSync を使用すると、1 つ以上のデータソースからのデータに安全にアクセス、操作、結合するための柔軟な API を作成でき、アプリケーション開発がシンプルになります。AppSync は、GraphQL を使用してアプリケーションが必要なデータを正確に取得できるようにするマネージド型サービスです。 AppSync を使用すると、NoSQL データストア、リレーショナルデータベース、HTTP API、AWS Lambda を使用したカスタムデータソースなどのさまざまなデータソース上で、リアルタイムの更新を必要とするアプリケーションを含む、スケーラブルなアプリケーションを構築できます。モバイルおよびウェブアプリケーションの場合、AppSync はさらに、デバイスのオフライン時にローカルデータアクセスを提供し、オンラインに戻るとカスタマイズ可能な競合の解決処理を使用したデータ同期を提供します。 引用: AWS AppSync公式 AppSync導入 amplify add api ? Please select from one of the below mentioned services: GraphQL ? Provide API name: amplifyApp ? Choose the default authorization type for the API API key ? Enter a description for the API key: ? After how many days from now the API key should expire (1-365): 7 ? Do you want to configure advanced settings for the GraphQL API No, I am done. ? Do you have an annotated GraphQL schema? No ? Do you want a guided schema creation? Yes ? What best describes your project: Single object with fields (e.g., “Todo” with ID, name, description) ? Do you want to edit the schema now? Yes AWS AppSync APIキーは作成後7日で有効期限が切れます。 初期設定後にAWS AppSync認証タイプを変更する場合は amplify update api コマンドを実行します。 amplify update api ? Please select from one of the below mentioned services: GraphQL ? Choose the default authorization type for the API (Use arrow keys) ❯ API key Amazon Cognito User Pool IAM OpenID Connect // 以下省略 amplify push コマンドを実行して、バックエンドにAPIを構築します。 そのあとにいくつか質問されますが、全てEnterでいきます。 amplify push current Environment: prod | Category | Resource name | Operation | Provider plugin | | -------- | ------------------ | --------- | ----------------- | | Api | amplifyApp | Create | awscloudformation | | Auth | amplifyappf9e59d08 | No Change | awscloudformation | | Hosting | S3AndCloudFront | No Change | awscloudformation | ? Are you sure you want to continue? Yes The following types do not have '@auth' enabled. Consider using @auth with @model - Todo Learn more about @auth here: https://aws-amplify.github.io/docs/cli-toolchain/graphql#auth GraphQL schema compiled successfully. Edit your schema at /Users/yuma/workspace/myapp/amplify-app/amplify/backend/api/amplifyApp/schema.graphql or place .graphql files in a directory at /Users/yuma/workspace/myapp/amplify-app/amplify/backend/api/amplifyApp/schema ? Do you want to generate code for your newly created GraphQL API Yes ? Choose the code generation language target javascript ? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.js ? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions Yes ? Enter maximum statement depth [increase from default if your schema is deeply nested] 2 GraphQL endpoint: https://xxxxxxxxxxxxxxx.appsync-api.ap-northeast-1.amazonaws.com/graphql GraphQL API KEY: xxxxxxxxxxxxxxxxxxxxxxxx この情報は src/aws-exports.js に自動的に挿入されます。 Amplify CLIで構築すると、 amplify/backend/api/amplifyApp/schema.graphql にデフォルトでTodoモデルを作成してくれるのでそのまま使います。 type Todo @model { id: ID! name: String! description: String } queries src/graphql/queries.js に標準的なクエリまで自動生成してくれます。 /* eslint-disable */ // this is an auto generated file. This will be overwritten export const getTodo = `query GetTodo($id: ID!) { getTodo(id: $id) { id name description } } ` ; export const listTodos = `query ListTodos( $filter: ModelTodoFilterInput $limit: Int $nextToken: String ) { listTodos(filter: $filter, limit: $limit, nextToken: $nextToken) { items { id name description } nextToken } } ` ; src/App.js を編集します。 import React , { useEffect } from 'react' ; import Amplify from 'aws-amplify' ; import awsconfig from './aws-exports' ; import { withAuthenticator } from 'aws-amplify-react' ; import { API , graphqlOperation } from "aws-amplify" ; import { listTodos } from "./graphql/queries" ; Amplify . configure ( awsconfig ) ; const App = () => { useEffect (() => { const getTodos = async () => { const todos = await API . graphql ( graphqlOperation ( listTodos )) console . log ( todos ) ; } getTodos () ; } , []) return ( <div > amplify - app < / div> ) ; } export default withAuthenticator ( App, true ) ; 何も格納していないので、空ですが無事に接続できました。     mutations src/graphql/mutations.js にこちらも自動生成してくれます。 /* eslint-disable */ // this is an auto generated file. This will be overwritten export const createTodo = `mutation CreateTodo($input: CreateTodoInput!) { createTodo(input: $input) { id name description } } ` ; export const updateTodo = `mutation UpdateTodo($input: UpdateTodoInput!) { updateTodo(input: $input) { id name description } } ` ; export const deleteTodo = `mutation DeleteTodo($input: DeleteTodoInput!) { deleteTodo(input: $input) { id name description } } ` ; src/App.js編集します。 import React , { useState , useEffect } from 'react' ; import Amplify from 'aws-amplify' ; import awsconfig from './aws-exports' ; import { withAuthenticator } from 'aws-amplify-react' ; import { API , graphqlOperation } from "aws-amplify" ; import { listTodos } from "./graphql/queries" ; import { createTodo } from "./graphql/mutations" ; Amplify . configure ( awsconfig ) ; const App = () => { const [ name , setName ] = useState ( '' ) ; const [ description , setDescription ] = useState ( '' ) ; const [ todos , setTodos ] = useState ([]) ; useEffect (() => { const getTodos = async () =>; { const { data } = await API . graphql ( graphqlOperation ( listTodos )) const { items } = data . listTodos setTodos ( items ) } getTodos () ; } , []) const handleCreateTodo = async () => { if ( ! name || ! description ) return setTodos ([ ... todos , { name , description }]) await API . graphql ( graphqlOperation ( createTodo , { input : { name , description }})) setName ( '' ) ; setDescription ( '' ) ; } const handleSetName = ( e ) => { setName ( e . target . value ) ; } const handleSetDescription = ( e ) => { setDescription ( e . target . value ) ; } return ( <div > amplify - app < label > name: < / label> <input name="name" type="text" value="{name}" onChange={ ( e ) => handleSetName ( e ) } / > <label > description: < / label> <input name="description" type="text" value="{description}" onChange={ ( e ) => handleSetName ( e ) } / > <button onClick = { () => handleCreateTodo ()} >add < / button> {todos.map (( todo, i ) => ( <p key={i}>name: {todo.name} description: {todo.description}</p> )) } < / div > ) ; } export default withAuthenticator ( App , true ) ; nameとdescriptionを追加できました。 今回は mutaions で値を格納しただけなので、リアルタイムではありませんが subscriptions を使えばでリアルタイムで反映されるのもAppSyncの良いところです。 おわりに AWSをあまり触ったことがない自分でも簡単に認証機能付きのWEBアプリを公開することができました。 今回使用したauthやapi以外にも amplify add xxx で一部のAWSリソースを使うことができます。 他にも色々触ってみたいなと思いました。 最後に、株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひ エンジニア採用サイト をご覧ください。
はじめまして、9月からスタメンにJoinさせていただいた @sokume です。 入社して数ヶ月ですが、熱い仲間たちとわくわくした日々を過ごしています。 今回は、スタメン本社のある名古屋ではなく、大阪で開催された Android Dev Summit 2019報告会 にLT登壇させて頂いたので、その話をさせていただきます。 Android Dev Summit '19 Android Dev Summit は Google が開催する Android 開発者のための技術イベント 今年は 10/23 、24 に Google Event Center[MP7] で開催 Android Dev Summit 2019 報告会 GDG Osaka が主催する、 Android Dev Summit '19で発表された技術を共有するためのイベント 今回が GDG Osaka の主催する初イベント :smile: メインセッション Google でRoom 1 の開発に従事されている方からの最新の発表や、今後の追加機能の話 Android Dev Summit `19 のセッション動画から気になった部分を掘り下げての説明 セッションの内容からすぐにプロジェクトに導入したいあれこれ といった内容がメインセッションの内容になります。 各セッションの内容まではふれませんが、Roomを使用した際のQuery処理の一覧は「額にいれて飾ろう」とか「公式のドキュメントにそのまま載せてほしい」というコメントがあるくらい有益な情報でした。(さすが中の人!) LT&懇親会 私もLT登壇の一人として「 Android Studio 4.0 つまみぐい!」という内容でお話をさせていただきました 内容としては、 Android Dev Summit '19で発表&リリースされた Android Studio 4.0 Canary 1 の新機能の検証をした内容になります。 ご興味のあるかたはご覧いただければと :smile: Android Studio 4.0 つまみぐい! from tsutomuhayakawa 懇親会もいろいろな方に話をしたり、話しかけて頂けたり、新しい繋がりもできとても有意義にすごせました 最後に 今回の登壇については、業務として参加させていただき、交通費等は会社に負担して頂き、大変ありがたかったです。 Android についての話をさせていただきましたが、スタメンでは他にもフロントエンド、バックエンド、デザインなどなど各分野の技術者が頻繁に外部での発信を行なっています。 今後もスタメンの技術者がいろいろな所で発信する機会があると思いますので、弊社メンバーを見かけた際はぜひお声がけください! スタメンに興味が湧いてきたという方は コチラ ご覧ください。 Roomは Android Architecture Componentsに含まれる SQLite データベースのラッパー  ↩
スタメン エンジニアの松谷( @uuushiro )です。 Rails アプリケーションにおいて認証機能にDeviseが利用されるケースは多いと思いますが、サービスの特性次第で メールアドレスをIDとした認証だけでなく、携帯電話番号をIDとした SMS認証、外部ソーシャルID連携や SAML 認証、MFA設定など多様な認証機能に対応する必要があります。その際にDeviseにモジュールを追加したりカスタマイズするなど、アプリケーション側で対応することも1つの手ですが、クリティカルな作業で 工数 がかかる割にはサービスの本質的な競争力の向上には繋がることは少ないです。できれば自前で実装するのは避けたいなと考えていたときに、 Amazon Cognito というアプリケーションで必要とする一連の認証機能を提供してくれるサービスを思い出しました。Deviseを利用した認証を Amazon Cognitoに委譲することで、実装コストを抑えることができそうだと思い調査してみました。 TL;DR (概要) Deviseを利用したユーザー認証を、 Amazon Cognito に委譲しました。主に Rails アプリケーション側で対応した内容と、 Amazon Cognito側で対応した内容の一部を共有します。 この記事では、 既にDeviseが導入されているアプリケーションの認証機能を Amazon Cognitoに委譲する想定とします。認証以外の機能(ヘルパー・ルーティング・コントローラー・セッション管理...etc)は引き続きDeviseを利用します。 認証フローは、 RFC 6749: 4.1. Authorization Code Grant で定義されている認可コードフローを採用しています。ここではOpen ID Connectに関する仕様の詳細は説明しません。必要な認証情報を Rails アプリケーションに設定をしている前提で説明をします。 認証の流れとしては、クライアントが Amazon Cognito に対して認証をし、その認証結果(認可コード)を Rails アプリケーションで受け取り、認可コードをID トーク ンと交換して、ID トーク ンの検証に問題が無ければWebサーバーがクライアントに対して Cookie (SessionID)を発行し、そのSession情報をサーバーに保存し、ログインします。 Rails アプリケーション側の対応 今回、 Amazon Cognito に委譲する Deviseの機能は以下3点です。 サインアップ・サインイン機能(database_authenticatable, :omniauthable, :registerable のモジュールが提供) ユーザー確認機能(:confirmableモジュールが提供) パスワードリセット機能(:recoverableモジュールが提供) Deviseには、独自の認証ストラテ ジー を追加できる機構があるので、それを利用してこれらの機能を Amazon Cognitoに移譲します。上記以外の、ルーティングやコントローラー、そしてセッション管理まわりの機能は引き続き、Deviseを利用します。 以下、UserモデルをDeviseで扱う場合のコード例です。 認証ストラテ ジー クラスの作成 lib/utils/devise/strategies/cognito_authenticatable.rbファイルを作成し、 Amazon Cognito の認証結果を受け取りアプリケーション側で検証・認証するストラテ ジー を作成します。ストラテ ジー クラスでは、authenticate! メソッドに認証ロジックを書き、valid?メソッドに認証をする条件を書きます。 valid?メソッドには、パラメータに認可コード(params['code'])が存在する場合 かつ 後述するstate値がセッションに記録されている値と一致すること を必須としています。 authenticate!メソッドには、認可コードを元に、認証情報が正当であるかどうかをチェックして、問題がなければWebサーバーがクライアントに対して Cookie (SessionID)を発行し、そのSession情報をサーバーに保存するという、Deviseによる認証後のフローと同じセッション管理をしています。 # lib/utils/devise/strategies/cognito_authenticatable.rb require ' devise/strategies/authenticatable ' module Devise module Strategies class CognitoAuthenticatable < Authenticatable def valid? # stateが一致(CSRF攻撃対策) && code が存在する の場合のみ認証処理に入る params[ ' code ' ].present? && params[ ' state ' ] == stored_state end def authenticate! # OpenIdConnect::UserAuthorizationは 認証情報を管理するクラス # OpenIdConnect::UserAuthorization.new.verify! の部分で適宜IDトークンの検証をする id_token = OpenIdConnect :: UserAuthorization .new.verify!(params[ ' code ' ], stored_nonce) sub = id_token.raw_attributes[ :sub ] user = User .active.find_by( sub : sub) success!(user) rescue StandardError => e Rails .logger.debug(e.message) fail ! end end end end モジュールの作成 Strategyに対応するDeviseのモジュールを作成し、対応するコントローラー・ルーティングを設定し、Deviseのモジュールに追加します。ここでは、Deviseがデフォルトで指定する、sessions_controller を Amazon Cognitoによる認証機能に対応させています。 # frozen_string_literal: true require ' utils/devise/strategies/cognito_authenticatable ' module Devise module Models module CognitoAuthenticatable end end end routes = [ nil , :new , :destroy ] Devise .add_module :cognito_authenticatable , controller : :sessions , route : { session : routes } コントローラーの修正 モデルの作成で、対応付けをした sessions_controllerを修正します。SessionsControllerのnewアクションがログイン画面に相当するため、 Amazon Cognitoがホストしている認証画面にリダイレクトするようにします。 また、 CSRF 攻撃を防ぐためのstate値と リプレイ攻撃 を防ぐためのnonce値をセッションに保存して、後に認証結果が渡ってきたときの検証に利用できるようにしています。 class Users :: SessionsController < Devise :: SessionsController def new redirect_to authorization_uri end private def authorization_uri # OpenIdConnect::UserAuthorizationは 認証情報を管理するクラス OpenIdConnect :: UserAuthorization .new.authorization_uri(set_state, set_nonce) end # CSRF 攻撃対策 def set_state session[ :state ] = SecureRandom .hex( 16 ) end # リプレイ攻撃対策 def set_nonce session[ :nonce ] = SecureRandom .hex( 16 ) end end state値とnonce値の説明については、以下の記事がわかりやすかったので必要があればご参照ください。 https://tech-lab.sios.jp/archives/8492 Deviseの設定 上の「認証ストラテ ジー の作成」で作成したStrategyをwardenに追加します。 また、デフォルトで使用する認証ストラテ ジー をuserスコープに限定して宣言をします。 # config/initializers/devise.rb require ' utils/devise/strategies/cognito_authenticatable ' config.warden do | manager | manager.strategies.add( :cognito_authenticatable , Devise :: Strategies :: CognitoAuthenticatable ) manager.default_strategies( scope : :user ).unshift :cognito_authenticatable end Userモデルも、追加したモジュールを利用するように変更します。 変更前は、Deviseのサインアップ・サインイン機能(database_authenticatable)、ユーザー確認機能(confirmable)、パスワードリセット機能(recoverable)も設定してありましたが、今後は Amazon Cognitoに移譲するため コメントアウト (削除)し、cognito_authenticatableのみにしています。 class User < ApplicationRecord # 以下のモジュールの機能は Amazon Cognitoが提供するので不要 # devise :database_authenticatable, :recoverable, :confirmable devise :cognito_authenticatable end Amazon Cognito から渡ってくる認証結果の受け口をつくる 認可コードフローの場合、認証結果として認可コードを Amazon Cognitoからアプリケーションが受け取り、検証をする必要があるので、それに対応するルーティング及びコントローラーを作成します。 # config/routes.rb namespace :auth do namespace :cognito do get ' /callback ' , action : :callback end end 以下のように authenticate!メソッド が呼ばれると、上で定義したストラテ ジー 内の、Devise::Strategies::CognitoAuthenticatable#valid?メソッドが呼ばれ、その結果がtrueの場合のみ、Devise::Strategies::CognitoAuthenticatable#authenticate!メソッドが呼ばれます。 module Auth class CognitoController < ApplicationController skip_before_action :authenticate_user! def callback resource = request.env[ ' warden ' ].authenticate!( :cognito_authenticatable , scope : :user ) redirect_to after_sign_in_path_for(resource) end end end ここまで簡単な説明でしたがアプリケーション側の説明は以上です。今後、認証方式を拡張する必要があったとしても Amazon Cognitoで対応可能な認証方式なら、アプリケーション側の認証インターフェースは変わらず対応可能です。 Amazon Cognito側の対応 スクリーンショット など設定画面の詳細は説明しませんが、アプリケーションの要件に合わせて Cognito User Poolの設定をします。アプリケーションとの連携時に必要なコールバックURLを、 Rails アプリケーション側の対応で、実装したAuth::CognitoControllerのcallbackアクションに対応するようにします。 これらの設定がうまく出来ていれば、認証が必要なページにアクセスすると、以下のような Amazon Cognitoが用意したログイン画面が表示されるので、この画面で Amazon Cognito User Pool に対して認証を行えば、その認証結果を Rails アプリケーション側が受け取り、ログインすることができます。 まとめ Deviseを利用した認証を Amazon Cognitoに委譲しました。そうすることで、 Rails アプリケーション側で実装していた、サインアップ・サインイン機能、ユーザー確認機能、パスワードリセット機能のコードが不要になりメンテナンスするコードを減らすことができました。 いままでDeviseを利用していて、以下のような問題を感じていました。 1点目は、ログインIDがメールアドレス前提の実装になっている箇所が多いことです。ユーザー確認URL・パスワード再発行などの通知はメール前提となっているので、電話番号をIDとしたSMS認証や、メールアドレス or 電話番号のどちらかをIDとするような、現在では一般的な認証IDに対応するために、Deviseのコードを読み解いてカスタマイズする必要がありました。 2点目は、外部ソーシャルID連携です。Deviseにはomniauthという機構が備わっており、外部ソーシャルID連携が認証プロバイダを介したユーザ認証方法によって標準化されています。omniauth系のgemを利用すれば外部ソーシャルID連携に対応することができるのですが、多少コードを書く必要があり、すべてのgemが活発に更新されているわけではないこともあって気軽には導入でません。 しかし、 Amazon Cognitoを利用すれば、上で言及したIDのパターンに対応しており、IDの種類に応じたメールや、SMSなどの通知機能にも対応しています。また、いくつかの外部ソーシャルIDプロバイダとの連携にも対応しており、選択するだけで簡単に利用することができます。その他もSAML2.0に対応していたり、MFAの強制ができたり、一般的に想定される認証のケースにほとんど対応することができます。今後、よほど複雑でない認証に関しては、自前で実装する前に Amazon Cognitoをまず検討してみると良いと思いました。 おわりに 今回 Amazon Cognitoを試してみて、とても簡単に認証機能を実現することができました。 Rails アプリケーションでDeviseを利用した認証を置き換える場合に参考になれば幸いです。 最後に、株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひエンジニア採用サイトをご覧ください。 wantedly