TECH PLAY

スマートキャンプ株式会社

スマートキャンプ株式会社 の技術ブログ

226

スマートキャンプで開発組織のマネジメントをしている米元です。 この10月でマネージャーになってからちょうど2年が経ちました。 マネージャーとして組織作りをする中で重要なものとして「採用」がありますが、そのプロセスは外部からはわかりにくく実際に選考を受けてみないと分からないことが多いのではないかと思います。 面談や面接では出来るだけ深くお互いの事を理解しミスマッチを無くすために時間を使いたいと考えており、会社全体としても会社説明資料などを公開して事前に候補者が内容を確認出来るようにしております。 その一環で当ブログでは約1年前に当時の採用フローを紹介しました。 tech.smartcamp.co.jp その後、この1年で様々なトライアンドエラーを行い改善を進めたため、現状のフローとは一致していない部分が出てきています。 そこで今回は改めて現在の採用フローについてご紹介したいと思います! 現在の採用フロー カジュアル面談(30〜60分) 目的 担当 内容 書類選考 技術試験(90〜120分) 目的 担当(結果の確認) 内容 一次面接(60分) 目的 担当 内容 二次面接(60分) 目的 担当 内容 リファレンスチェック 目的と内容 入社体験、見学 目的 担当 内容 期待値の擦り合せ面談(15分〜30分) 目的 担当 内容 最終面接(30〜60分) 目的 担当 内容 1年前と変わった点 各面接での目的を明確にした 技術試験を始めた 性格診断を無くした 説明資料をアップデートした マネーフォワードグループにジョインした 選考がリモートで完結するようになった オンボーディングが整備されてきた コーポレートサイトにエンジニア採用ページができた まとめ 現在の採用フロー 2020年10月時点での基本的な採用フローは以下のようになっています。 内容や順番は変わる場合があります。 カジュアル面談(希望者のみ) 書類選考 技術試験 一次面接 二次面接 入社体験・メンバーとの面談(希望者のみ) リファレンスチェック 期待値の擦り合せ面談 最終面接 オファー ステップが多く見えるかもしれませんが、候補者の都合に合わせて複数の面接や面談を1日にまとめるなど全体のリードタイムを短くする工夫もしています。 また、コロナ禍以降は基本的に全工程をリモートで行っております。 ここからは上記の1つ1つの目的と内容を説明していきます。 カジュアル面談(30〜60分) 目的 候補者に弊社の事を理解して頂き、選考に進むうえでの不明点を無くしたうえで興味を持てるかを判断して頂く 担当 開発組織の責任者(私)もしくは希望があった場合は他のエンジニア1,2名 内容 選考要素の無い「カジュアル面談」もエンジニアが担当します。 基本的に私が担当することが多いですが、希望によってはチームのメンバー数名でお話することもあります。 カジュアル面談では簡単な自己紹介をした後に特に話したい事を候補者の方に確認し、それに応じて説明の内容を調整しています。 説明用のスライドを用意しており、基本的にはそれを見ながら話をして気になる箇所があれば随時聞いてもらうようなスタイルで進めています。 主な内容は以下のとおりです。 会社概要 ビジョン・ミッション 事業内容 開発で注力していることや課題 プロダクトごとの開発チーム体制、利用技術、開発の進め方 開発組織全体の文化 技術広報 合宿やLTなど社内での活動など、最近の取り組み 一通り話した後に改めて全体を通して質問を聞いて、そのあと時間があれば弊社から以下のような質問をさせて頂く事が多いです。 転職活動状況(情報収集か積極的に活動しているのか) 活動中の場合はどんな軸で企業を見ているのか 好む環境やカルチャー 中長期でやりたいこと、なりたい像 得意な技術、興味のある技術 ただ人によってはひたすら技術の話で盛り上がって終わるケースがあったりと、特に上記の内容にこだわっている訳ではありません。 「目的」にも書いていますが、カジュアル面談では候補者の方に弊社のことを良く理解していただき、そのうえでマッチするかどうかや興味が持てるかどうかを判断頂くことが一番大事です。 それが達成できればどのような内容でも良いと考えています。 書類選考 履歴書や職務経歴書を提出していただき、それをもとに選考を行います。 コーポレートサイトからの直接応募の場合やエージェントさんからの紹介の場合などは書類選考から開始になる場合が多いです。 技術試験(90〜120分) 目的 候補者がどの領域にどのようなスキルや知識があるかを事前に判断するための材料とする ※この試験自体での合否は出していません 担当(結果の確認) 一次面接の担当者 内容 オンラインで自宅等で受験可能な外部サービス( track )を利用しています。 試験の内容は 主に知識を問う選択問題 プログラミングスキルを確認するコーディング問題 これまでの経験や知識を確認する記述式問題 の3つです。 採用ポジションや時期によって内容を変更しています。 候補者の負担になるため辞退率が上がる懸念もあったのですが、今のところそこまで辞退率への影響は無いようです。 まだ始めて3ヶ月程度で試行錯誤中ではあるので、目的も含めて今後変わる可能性があります。 一次面接(60分) 目的 候補者が募集中のポジションで活躍出来るスキルや経験をお持ちなのかどうかを判断する 担当 お任せする予定のプロダクトのエンジニアリーダーとエンジニアメンバーの2名 内容 技術試験の結果やレジュメなどの話をもとに候補者のスキルやご経験を確認します。 技術試験の結果に関しては、なぜこのように回答したのか・他にはどんなケースが考えられるかなどのようにディスカッションも交えてお話させて頂き、実際に一緒にお仕事をする際にどのようなコミュニケーションをとることになるかも確認させて頂いています。 二次面接(60分) 目的 候補者が弊社のカルチャーにマッチするかを確認する 担当 お任せする予定のプロダクトのプロダクトマネージャーと担当役員の2名 内容 主に人間性や考え方・行動力・価値観などを知るための質問が中心になります。 判断基準としては以下の4つの行動指針(社内ではそれぞれの頭文字をとって「SOCS」と呼んでいます)を基準として弊社のカルチャーにマッチするかを判断させて頂きます。 SmartThinking 仮説思考・本質思考 先見性と創造性 Ownership リーダーシップ 主体性 Collaboration 社内・社外共創 Speed 実行スピード 生産性(質/時間) リファレンスチェック 目的と内容 過去一緒に働いたことがある方からアンケート形式でお仕事ぶりや人物像をお伺いし、面接だけでは把握しきれない側面を理解する目的で行っています。 弊社では backcheck という外部サービスを利用しており、弊社の事例を紹介して頂いた記事もありますので興味がある方はご覧ください。 backcheck.jp ※エンジニア職の事例ではありません なおリファレンスチェックの結果のみで採用判断を行うことはありません。 入社体験、見学 目的 面談や選考での印象と実際の業務中の様子にギャップが無いかを確認し入社後のイメージをつけて頂く 担当 受け入れ予定のチーム全体 内容 以前は1日がっつりスケジュールを組んで業務体験や会議への参加をして頂いていましたが、最近はスクラムの一部のセレモニー(スプリントレビューや振返りなど)に参加して頂く事が多いです。 入社体験用のプログラムを作って参加して頂くよりも普段から行っているセレモニーに参加して頂く事で チームやプロダクトの課題 今やっていること 普段のチームでのコミュニケーション などが良く伝わるのではないかと考えており、実際に参加者からもそのようなフィードバックを頂いています。 期待値の擦り合せ面談(15分〜30分) 目的 入社後に求める役割や中長期でのキャリア、働き方などの条件がマッチしているかを擦り合せする 担当 開発組織の責任者(私) 内容 選考要素が無い面談です。 二次面接以降で最終面接までのどこかのタイミングで実施します。面接と同日に行う場合もあります。 弊社からは改めて期待する役割や弊社での中長期のキャリアイメージについて話をさせて頂きます。 基本的にはここまでの選考の中で確認は出来ている想定ですが人によって選考の初期の段階から変わっている場合があるため、この段階で確認し擦り合せを行います。 最終面接(30〜60分) 目的 事業の方向性や経営者との目線合わせ 担当 CEO 内容 弊社の事業の方向性や経営視点での開発に対する期待などをお話させて頂きます。 1年前と変わった点 ここまでが現在のフローでした。 ここからはどこが1年前と変わったのか、そして変えた結果どうなったのかについても個別に紹介していこうと思います。 各面接での目的を明確にした 以前は面接ごとの目的は特に決めず、一次で聞き切れなかったことを二次で聞いて候補者の理解を深めていくような進め方でした。 ただ一次と二次の面接官同士での質問内容の確認コストがかかったり、合否の基準が曖昧になるなどの課題があり現在の形に変えました。 現在の形に変えてからはそれぞれの面接で何を話すかが明確になり、短時間で効率よくかつ深い話が出来るようになりました。 技術試験を始めた レジュメでは分からないような得意/不得意や課題へのアプローチ方法が面接の前段階である程度把握できるようになり、以前よりも面接の時間を有効に使えるようになりました。 まだ始めたばかりなので適宜見直しつつ改善していく予定です。 性格診断を無くした 正確には選考中のフローからは一旦外しました。 技術試験を始めた事と、リファレンスチェックがそれなりに時間がかかる事、それらに加えて性格診断も実施するとあまりに候補者の負担が大きいことからエンジニア採用に限っては性格診断は実施しない事にしました。 性格診断自体は配属後の業務内容や活躍イメージがしやすくなるため有効ではあるものの、リファレンスチェックでも同じような効果が望める事も実施をやめた理由の一つです。 説明資料をアップデートした 一年前と組織の人数や体制、会社やプロダクトの状況が変わっているため、カジュアル面談で使用している説明資料を何度かアップデートしました。 説明しながら伝わりにくい点や自分が話づらいと感じる点は随時改善しています。 マネーフォワードグループにジョインした 昨年の11月にマネーフォワードグループへジョインしました。 採用フローに大きな影響があったわけでは無いのですが、会社としては一番大きな変化でした。 候補者からも影響や変化についてよく質問して頂きます。 開発組織としては グループ内の技術面・組織面のノウハウを得られる 技術的な課題の相談ができる 内部の勉強会など学べる環境が広がる 技術系のイベントを共催できる などがメリットとしてありました。 選考がリモートで完結するようになった 紹介したフローは基本的に全てリモートで行っています。 8月に入社したメンバーとは入社後に初めて対面で話しました。 今のところお互いに入社前後でネガティブなギャップは感じていないので、リモートのみでの選考でも問題ないと感じています。 とは言え候補者にとっては会社の雰囲気を知るためにオフィスを見たいという気持ちもあるので、その場合はオフィスでお話する機会を作ることもあります。 オンボーディングが整備されてきた 昨年の記事以降、入社後のオンボーディングについて全社的にも開発組織的にも整備が進み、入社後に出来るだけ早く成果を出して頂けるような仕組みが出来てきました。 例えば入社後の最初の2週間はメンターが1on1を毎日15分行い、業務外も含めて分からない事や困っている事がないかを確認するようにしています。 また、タスクもなるべく本人が成果を出しやすいものからアサインし、本人が自信をつけると共に周囲にも成果を出せるという事を見せられるようなお膳立てをすることを意識しています。 通常でも転職後すぐに成果を出すことは難しい事なので、リモート中心となった現在は今まで以上に新入社員の方へのサポートに注意を払っています。 コーポレートサイトにエンジニア採用ページができた メンバーからの提案で人事やデザイナーの協力のもと素敵な採用ページを作って頂きました。 smartcamp.co.jp 今まで弊社のコーポレートサイトには募集求人ごとのページはあったものの、開発組織を紹介するようなページはありませんでした。 そのため簡単に説明することが難しかったのですが、これが出来たことによって社外の方にもURLをお渡しするだけで良くなり、開発組織の全体観を伝えやすくなりました。 まとめ スマートキャンプの採用フローを一年ぶりに紹介しました。 「採用後の活躍がゴール」という意識は変わっていませんが、それに至るまでのプロセスは常に改善し続けています。 改善の過程では私だけでなく他の開発メンバーも一緒に日々試行錯誤しています。 チームや事業のため、更には候補者により良い体験をしてもらうために、採用活動に主体的に取り組んでくれているメンバーには感謝しかありません。 今後もチームで協力して採用活動に取り組んでいきたいと思います。 ここまでの記事を読んで弊社の話を聞いてみたい!と思った方は、ぜひお気軽にご連絡ください。 [再掲] smartcamp.co.jp
アバター
こんにちは!フリーランスエンジニアの曽根田です。 本日は「Let'sリファクタリング!!」ということで、以下の内容でお届けさせていただきます。 はじめに ボクシル開発チームで取り組んできたこと リファクタリングに取り組むにあたっての背景 リファクタリングコードのサンプル Let's リファクタリング DB への問い合わせの削減(N+1 対策) 対策 1: categories と category_setting_items を予め読み込んでおき、キャッシュさせておく 対策 2: product_category_settings を予め読み込んでおき、キャッシュさせておく/ view での SQL の発行を止める 改善結果 view のコンポーネント化 未使用の関数の削除 外部キー制約をつける NOT NULL 制約をつける test コードを書く まとめ はじめに スマートキャンプさんには 2020 年 4 月から業務委託としてBOXIL開発チームの一員としてジョインさせていただきました。 スマートキャンプさんでは、 前向きに意見交換し、問題解決・プロダクト改善に取り組むことのできる文化 があります。 スマートキャンプさん主催の B2B SaaS エンジニア Meetup イベントに登壇させていただき、それをきっかけに交流が始まりました。 素晴らしい文化を持つ開発チームの一員として、実際に一緒にお仕事をすることができるのを大変嬉しく楽しく思っています。 (受け身のような働き方になるのかなと思っていたのですが全く違った!) tech.smartcamp.co.jp ボクシル開発チームで取り組んできたこと さて、参戦させていただいてから今までの半年間で、ボクシル開発チームでは様々なことに取り組んできました。 大きく分けると以下に分類されます。 新機能の開発 デザインリニューアル インフラのアップデート 日々の改善タスク 今回は「 日々の改善タスク 」の中で取り組んできた リファクタリング についてご紹介したいと思います。 (※ 実際のコードではなくサンプルコードを用いて紹介します ) また今回紹介させていただく リファクタリング のスコープは、 アプリケーションコードの改善 を中心とします。 不要ファイルの削除 view のコンポーネント化 パーフォーマンスの改善(主に N+1) DB のリファクタリング(小規模) ドメインの責任範囲の整理 test コードを充実させる 次項の技術スタック概要紹介の画像にもありますが、 現在 BOXIL 本体で採用されている言語は Ruby であるため、サンプルのコードは Ruby で記載します。 (フレームワークは Ruby on Rails ) 中上級者の方にとってはあたりまえに思える内容かもしれません。また、派手な話ではないですがご了承いただけると嬉しいです。 リファクタリングに取り組むにあたっての背景 BOXIL のサービスは 2015 年から運営されており、すでに 5 年の歴史があります。 以下の画像は現在 BOXIL 開発チームで運用している技術スタックの概要になります。 SmartCamp BOXIL 技術スタック BOXIL の PM である笹原さんの記事にもありますが、最近ではエンジニアの人数が今までの 3 倍となり、 改善の規模や内容が濃くなってきております。 エンジニアとしては面白い時期なのではないでしょうか? 新言語の採用なども検討中のようです。 tech.smartcamp.co.jp とはいえ、 現行動いているアプリケーションが少なくともしばらくは稼働すること アプリケーションが整理されている状態が今後の濃い改善への足がかりになること を考えると日々の リファクタリング は非常に重要な取り組みになります。 また日々の リファクタリング をするにあたって、BOXIL 開発チームでは特に以下を意識して取り組んでいます。 不明なドメインを明確化させていくこと 可能な範囲で制約を取り入れていこと 可読性が良く、パフォーマンスが極端に悪くないこと リファクタリングコードのサンプル こちらにサンプルのコードを用意しました。 特にアプリケーションの仕様に意味はありません。 課題をわかりやすく、少しダメなコードを書いています。 github.com 以下の順番でリファクタリングを進めていきます! DB への問い合わせの削減(N+1 対策) 対策 1: categories と category_setting_items を予め読み込んでおき、キャッシュさせておく 対策 2: product_category_settings を予め読み込んでおき、キャッシュさせておく/ view での SQL の発行を止める 改善結果 view のコンポーネント化 未使用の関数の削除 外部キー制約をつける NOT NULL 制約をつける test コードを書く 以下はそれぞれリファクタリング前後を比較するためのブランチと差分です。 リファクタリング前のブランチ(before_refactor) リファクタリング後のブランチ(master) リファクタリング前のブランチとリファクタリング後のブランチの差分 Let's リファクタリング DB への問い合わせの削減(N+1 対策) http://127.0.0.1:3000/products へアクセスし、 rails server の log を覗いてみましょう。 なにやら 大量の SQL が発行 されています。 発行される大量のSQL 対策 1: categories と category_setting_items を予め読み込んでおき、キャッシュさせておく [対応 PR]DB への問い合わせの削減(N+1 対策)-NO1 https://github.com/soneda-yuya/refactoring_sample/pull/1 ActiveRecord の性質上、ActiveRecord に実装されてある includes や preload を使わないと簡単に N+1 のデータベースアクセスが発生しています。 かといって何でもかんでもキャッシュするのはパフォーマンス上良くなく、基本的には使用するもののみキャッシュするのが良いです。 改善1: categories/category_setting_itemsテーブルへのアクセスが減りました 対策 2: product_category_settings を予め読み込んでおき、キャッシュさせておく/ view での SQL の発行を止める [対応 PR]DB への問い合わせの削減(N+1 対策)-NO2 https://github.com/soneda-yuya/refactoring_sample/pull/2 よく見かけるのが、Model 内に定義された便利関数を view 内で多用しているケースです。データベースにアクセスしないものであれば良いのですが、関数内でデータベースへのアクセスを行っている関数も時々みられます。(データ有無のチェックなど) 実際に使用する際は、関数内の定義がどのようなものなのか、しっかり把握した上で view 内で関数を呼び出しましょう。 データベースへのアクセスを行っている関数を view 内で呼び出さないといけないケースが出てきた際は、他に良い実装方法がないかを検討することをおすすめします。 また余裕があれば、その関数を使用している箇所を リファクタリング してあげてください。 改善2: product_category_settingsテーブルへのアクセスが減りました。 改善結果 かなりパフォーマンス改善が行えました。 あえてダメなコードを書いているサンプルコードなので、これだけの差が出ているのですが、 実際のプロダクトでも DB への問い合わせの削減(N+1 対策)を意識することで、大幅なパフォーマンス改善に繋がることもあります。 ぜひ意識してみてください。 改善前のパフォーマンス 改善後のパフォーマンス view のコンポーネント化 http://127.0.0.1:3000/products と http://127.0.0.1:3000/categories にアクセスしてみてください。 http://127.0.0.1:3000/products http://127.0.0.1:3000/categories よく見ると(よく見なくても)赤枠の部分が同じ内容ですね。 view をコンポーネント化し、共通で使用することによって、修正漏れを防げたり、管理が楽になるメリットがあります。 [対応 PR]view のコンポーネント化 https://github.com/soneda-yuya/refactoring_sample/pull/3 スマートキャンプさんではデザイナーとエンジニアはすごく寄り添いながらプロジェクトを進めています。 あるプロジェクトでは Atomic Design と Figma を組み合わせ、プロダクト開発しやすいデザインシステムを採用している事例もあります。 React や Vue が登場しだしてからは、コンポーネント化が当たり前の時代になってきているので、デザイナーさんと今まで以上に結束力を高めましょう! そうすればより実装しやすいデザインになり実装スピードも上がるはずです。 note.com 未使用の関数の削除 おや、 viewのコンポーネント化 の作業の際に使用しなくなった関数がありました。 またコードを読んでいると使ってなさそうな関数があります。 どうやら修正や機能開発の際に、未使用になった関数がそのままになっていることがよくあるようです。 [対応 PR]未使用の関数の削除 https://github.com/soneda-yuya/refactoring_sample/pull/4 新たな機能を開発する際や、 リファクタリング 際に未使用の関数が残っていると影響範囲の調査に一手間かかってしまうことがあります。 未使用な関数は積極的に消していきましょう。 外部キー制約をつける おっと。開発中に不具合が発生しました。 予期せぬ不具合 調査を進めると Products テーブルの以下のデータが原因であることがわかりました。 Products テーブル id category_id name 1 8000 Borvo the Hutt どうやら存在していないカテゴリーが登録されているようで、 product.category でカテゴリーを参照しようとした際に NULL になっていそうです。 カテゴリーの削除機能もないので、存在しないカテゴリーが設定できるはずがありません。おそらく開発中に意図せず値を変更してしまったのかもしれません。 意図しない値は許容しないように、関連するテーブル同士に 外部キー制約 を貼ることで、今後このようなことが起きないようにしましょう。 [対応 PR]外部キー制約をつける https://github.com/soneda-yuya/refactoring_sample/pull/5 今回は開発中に気づいたので、再度 seed でデータを作成し事なきをえました。 既に本番データで不整合が発生してしまった場合は、その状態で 外部キー制約 を貼ろうとしてもデータベース側のエラーで実行できません。 そのため、データの整合性を整えてから実行する必要があります。 外部キー制約 については貼る貼らないの宗派がありますが、個人的にはデータの整合性を担保するために積極的に 外部キー制約 を貼る事をおすすめします。 NOT NULL 制約をつける ふとデータベースをみていると見慣れないレコードを発見しました。 NULL が存在するはずのないテーブルに NULL が登録されてしまっています。 おそらく開発中に意図せず値を変更してしまったのでしょう。 意図しないデータが登録できることは良くないので、こういったカラムには NOT NULL 制約 を付けましょう。 NULL? [対応 PR]NOT NULL 制約をつける https://github.com/soneda-yuya/refactoring_sample/pull/6 もちろん全てのカラムに NOT NULL 制約 をつければ良いのかというとそういうわけではありません。 NULL を許容するかどうかをよく吟味し制約をつけていきましょう。 test コードを書く 開発をしていて、そういえば test コード どうなってるんだろ...みてみるとない!....みたいなことは時々あるかと思います。 その時の状況でどうしても時間がなかったなど理由があったのだと思います。 test コードがないコードを見つけた時は、積極的に楽しんで test コードを追加していきましょう! [対応 PR]test コードの追加 https://github.com/soneda-yuya/refactoring_sample/pull/7 慣れてくると開発時に test コード を書く方が効率が良くなってきます。 test コードは通常のコードの記法と少し違い、学習コストが少しかかるかもしれません。 ただし、それ以上の費用対効果を得ることができるので、早いうちに慣れることをおすすめします。 まとめ 上記のサンプルもまだまだ改善の余地がありますが、いかがでしたでしょうか? BOXIL 開発チームでは新しい技術への挑戦も積極的ですが、上記のような改善にも日々取り組んでいます。 短期的にみると 早くコードを書くこと が優先されますが、長期的な目線で見ると 品質の高いコード がより生産性をあげてくれます。 Let's リファクタリング!! 最後まで読んでいただきありがとうございました!
アバター
ボクシルのプロダクトマネージャーをしている笹原です。 ボクシルの開発チームは今年に入ってから規模をかなり拡大してきました。 一番少なかった2月と比べて3倍近い規模になり、拡大傾向も落ち着かせるフェーズになってきました。 そこで、今回はチームの規模を拡大する中で起こったことや、それに対してどのように対応してきたのか振り返って行きたいと思います。 併せて読んで欲しい記事 昨年の12月に同じように振り返ったときの記事です。 tech.smartcamp.co.jp 2020年2月〜: 2チーム制 この時期の体制 リモートワークへの対応 2020年4月〜: 1チーム制 この時期の体制 チーム内のコミュニケーションコスト増加 2020年6月〜: 3チーム制 この時期の体制 ストーリーポイントの安定化 ボトルネックが開発から企画へ 2020年9月〜現在: プロジェクトチーム制 この時期の体制 まとめ 2020年2月〜: 2チーム制 この時期の体制 プロダクトマネージャー1人 デザイナー1人 エンジニア3人 このときはサービスの根幹である資料請求に関する仕様変更のプロジェクトが走っていました。 他部署からの要望や緊急対応があってもプロジェクトの進捗に影響がないように、プロジェクトチームと要望対応・運用チームとに分割しています。 エンジニアが3人しかいなかったこともあり、プロダクトマネージャーがエンジニアを兼務する形で2チーム体制としていました。 リモートワークへの対応 この時期は弊社に限らず多くのチームがリモートワークへの対応に追われていたのではないでしょうか。 3月から全社的にリモートワークすることを選択し、フローが一部変わる部分もありました。 チームの振り返りなど、集まって付箋を使ったワークなどが影響を大きく受けましたが、デザイナーがすぐにFigmaにテンプレを作成してくれて助かりました。 今ではKPTに限らずLean Coffeeなど、他の振り返り手法用のテンプレートも用意され、リモートでも十分に振り返ることができています。 note.com 2020年4月〜: 1チーム制 この時期の体制 プロダクトマネージャー1人 デザイナー1人 ディレクター1人 エンジニア5人 4月から業務委託の方とインターンの方に1名ずつエンジニアとして入ってもらいました。 エンジニアのメンバーが増えたこともあり、この頃からプロダクトマネージャーが開発から離れています。 このときは口コミ機能のリニューアルをしていたのですが、口コミ収集の開始を早めたかったこともあり、1チームにして口コミ機能に集中していました。 また、入って間もないメンバーが半数以上を占める形になったので、2チームだと他のメンバーをサポートしづらかったことも、1チームにした理由の1つでもあります。 チーム内のコミュニケーションコスト増加 1チームの人数が増えたことによってチーム内のコミュニケーションコストが増加しました。 業務委託やインターンの方はフルタイムでの勤務ではないこともあり、情報の共有を通常よりも重要視していたこともそれを加速させていました。 リモートになったこともあり、今までは口頭でのやり取りだけだったものも背景とともにドキュメントに残すようになりました。 2020年6月〜: 3チーム制 この時期の体制 プロダクトマネージャー1人 デザイナー1人 ディレクター1人 エンジニア8人 6月には社内の他チームから3人移ることになり、8人と更に人数が増えました。 もともとチームの人数が多く、開発チーム内のコミュニケーションコストが高くなっていたこともあり、3チームに分割することにしました。 ストーリーポイントの安定化 この頃から、チーム全体のストーリーポイントが安定しやすくなってきました。 ストーリーポイントの安定のしやすさとチーム全体の規模には一定の相関関係がありそうだと思います。 今回、チーム全体のストーリーポイントが安定したのは、チーム全体がある程度の規模になったことで、1スプリント内で発生する以下のような振れ幅を吸収しやすくなったことが理由ではないかと思います。 タスクごとに振れ幅 各人のパフォーマンスも振れ幅 使える時間にも振れ幅 一方で、予測できなかったことやプロセスのボトルネックも吸収できてしまうので、そういったことが隠れやすくなってしまうとも考えられます。 ボトルネックが開発から企画へ 開発チームは3チーム体制になったものの、その開発チームへのインプットとなるPdM、デザイナー、ディレクターは1チームで動いていました。 1チームで3チーム分の企画をしていましたが、次第に開発に企画が追いつかないようになってきました。 2020年9月〜現在: プロジェクトチーム制 この時期の体制 プロダクトマネージャー1人 デザイナー1人 ディレクター2人 エンジニア9人 6月以降、人数が増え、チームが増え、開発のアウトプットが増えたことで企画がボトルネックになっていました。 そこで、プロジェクトごとに企画のオーナーを決め、各プロジェクト内での意思決定をそのオーナーがするようにしました。 エンジニアがオーナーとしてすすめるプロジェクトもすすめることで、より自律的なチームにしていこうとしています。 まとめ この半年間のボクシルの開発チームの変遷を課題や発見とともに振り返ってみました。 エンジニアの人数としては3倍になっており、その数字だけでもこの半年間で大きくチームの形が変わったことがおわかりいただけるのではないでしょうか。 そのときどきで課題は発生していたものの、それだけ変わったにも関わらず大きな問題が発生していないのは、以下のような点が寄与していると思います。 採用時にカルチャーマッチを重視している点 入社後のオンボーディングが手厚い点 スクラムの考え方が各メンバーにインストールされている点 弊社の採用やオンボーディング、開発プロセスについてもっと知りたい方は以下の記事もご覧になってください。 tech.smartcamp.co.jp tech.smartcamp.co.jp tech.smartcamp.co.jp
アバター
こんにちは!スマートキャンプでインサイドセールスに特化した SaaSを作っているエンジニアの井上です。 携わっている上記のプロダクトは使いやすさにこだわっているため、UIの修正を行うことが多々あります。 そんななかで起こった問題の対応としてビジュアルリグレッションテストを導入したので、今回はその話をできればと思います。 背景 ビジュアルリグレッションテストとは? ビジュアルリグレッションテストをやる目的 何をテストをするのか? 使用したツール Cypress reg-suit 画像を取得する 画像の差分を検知する Circle CIによる自動化 ベース画像の自動更新 ビジュアルリグレッションテストの実行 ハマったところ 結果どうなったか reg-suitの結果画面 今後の改善・取り組みたいこと 背景 ビジュアルリグレッションテストを導入する前に、UIに大きく影響する改修がありました。 影響範囲が多岐に渡る改修だったので、全画面をテストする必要がありましたが、画面ごとの表示崩れが無いかを確認する作業がとても苦行で、かつ時間もかかってしまいました。 また、その後もボタンが表示されていないなどの問題が発生してしまったことから、以下を検討しました。 UIテストの自動化によるテスト工数削減 意図しないUI変更の検知をする仕組みの導入 ビジュアルリグレッションテストとは? コンポーネントやページのスクリーンショットを、事前に用意した正解の画像と比較することで、ピクセルレベルでの差分を検出するテスト手法のことです。 ビジュアルリグレッションテストをやる目的 目的としては、人力によるチェックの負担を軽減するところにあります。 今回の背景にもあったUIテストの工数削減と意図しないUI変更の検知です。 特に、修正した内容をエンジニアが意識しなくても自動でテストしてもらうことで工数の削減をしたいなと思いました。 今回はその手段としてビジュアルリグレッションテストを実施することに決めました。 何をテストをするのか? 変更が多く、かつ使われてることも多い箇所をテスト対象にしていくことが重要だと思っています。 しかし、いきなり全てのテストをやるのは工数がかかりすぎるので短期でできて効果が高いものをスタートとして、まずはページ単位での表示崩れを検知できることを目的にしました。 使用したツール Cypress Cypressはブラウザでのテストを自動化するテストフレームワークです。 立ち上がると、テストコードを更新する度にホットリロードがかかりテストが実行されることが個人的に嬉しいです。 もともとE2Eテストの文脈で導入していましたが、スクリーンショット機能がある、かつ今回の対象がページ単位のテストのためCypressで画像の取得を行うことにしました。 reg-suit 画像群を比較し、レポート作成するまでの責務を持ちます。 Cypress内でビジュアルリグレッションテストまで行ってしまうことは可能ですが、"画像の取得"と"比較"の役割を分けられるというメリットがあります。 なので、今回作った画像比較の仕組みは、画像取得の部分さえ変えれば比較ロジックはそのままreg-suitを使用できます。 また、reg-suitにはプラグインを通してSlackやgithubとの連携も可能です。 今回使ったプラグインは以下のものになります。 reg-simple-keygen-plugin スナップショットキーとして任意の文字列を指定できる reg-publish-s3-plugin レポートをS3にアップロードする reg-notify-slack-plugin レポートをslack通知する 画像を取得する ビジュアルリグレッションテストをするにあたり、比較元になる正解の画像(EXPECTED)とUI修正後の画像(ACTUAL)の2つが必要です。 前述した通り、今回はCypressのスクリーンショット機能を使って取得しますが、正解画像とUI修正画像はreg-suit側で判断するため、Cypressはシンプルに画像を取得するのみになります。 /// <reference types="cypress" /> context( 'Actions' , () => { beforeEach(() => { cy.visit( 'http://localhost:3000' ) } ) it( 'top screenshot' , () => { cy.screenshot( "test" ) } ); } ) 画像の差分を検知する 今回作成したreg-suitによる画像の差分検知では、以下のようなフローで差分を検知します。 フォルダ名がEXPECTED_KEYの正解画像をS3から取得 Cypressで取得した画像とS3から取得した画像を比較 比較結果をACTUAL_KEYをフォルダ名としてアップロード Slackに比較結果を通知 実際使用した設定は以下のようなものです { " core ": { " workingDir ": " reg ", " actualDir ": " cypress/screenshots ", " threshold ": 0 , " ximgdiff ": { " invocationType ": " client " } } , " plugins ": { " reg-simple-keygen-plugin ": { " expectedKey ": " ${EXPECTED_KEY} ", " actualKey ": " ${ACTUAL_KEY} " } , " reg-publish-s3-plugin ": { " bucketName ": " ${BUCKET_NAME} " } , " reg-notify-slack-plugin ": { " webhookUrl ": " ${WEBHOOK_URL} " } } } Circle CIによる自動化 画像の検知の仕組みをCircle CIのフローにのせていきます。 CIでやることとしては2つで、ベース画像の更新とページごとのビジュアルテストです。 ベース画像の自動更新 ベース画像の更新はエンジニアが意識せずとも最新の状態になるようにしたいと考えたため、Gitのmasterブランチにマージされたタイミングでベースの画像更新をしています。 ビジュアルリグレッションテストの実行 ビジュアルリグレッションテストの流れとしては テスト環境へCypressが画像を取得(Actual Image) reg-suitがS3に保存している正解の画像(Expected Image)を取得 reg-suitで画像の差分テスト reg-suitのテスト結果をS3に保存 最終的な Cypress と reg-suit のテストフロー図 ハマったところ デフォルトの状態ではCircle CIに日本語フォントがないため、ページの日本語が豆腐文字(□□□)になっていました。 Circle CIに日本語フォントをインストールすることで解決しました。 E2Eなどでのあるあるですが、画像の取得が安定せず苦戦しました。 特定の秒数waitさせる力技により安定させました。 結果どうなったか ピクセル単位で差分を検知できる状態になり、masterマージ時にベース画像が更新されるのでエンジニアが意識せずともリソースを最新の状態に保てる形になりました。 reg-suitの結果画面 今後の改善・取り組みたいこと 今回はページごとのテストでしたが、変更の多いUIのすべてをテストできる形にし、より予期せぬ変更を検知できる形にできればなと思います。
アバター
こんにちは!スマートキャンプで インサイドセールスに特化した SaaS を作っているエンジニアの中川です。 上記プロダクトのフロントエンドは Vue.js を用いて開発しているのですが、 その中で SFC 内の template タグで使用していた Pug をやめて HTML に移行した件をこの記事ではお話しようと思います。 また、実際に template タグに ESLint を効かせてみて発覚したエラーや警告のなかで数が多かったものや、これから Vue 3 に移行していく上で対応する必要があったルールを紹介します。 背景 eslint-plugin-vue が効かない チームに Pug 推進派がいない Pug を HTML に移行するには Vue 3 に準拠した Lint ルールを導入する Lint を実行してみる 対応した目ぼしいルール vue-require-v-for-key vue/valid-v-slot templateタグ以外に対してv-slotを使用していた問題 そのほか Vue 3 にアップグレードするまで対応出来なかったルール vue/no-deprecated-v-bind-sync vue/no-deprecated-v-on-native-modifier vue/no-deprecated-destroyed-lifecycle vue/no-deprecated-functional-template まとめ 背景 まずは、なぜ Pug から HTML に移行する判断に至ったのかについて理由を説明します。 eslint-plugin-vue が効かない いきなりですが、これが最大の理由です。 eslint-plugin-vue は、読んで字の如く、ESLint のプラグインとして .vue ファイルの Lint を行えるようにするものであり、公式のプラグインも用意されていてデファクトスタンダードとなっています。 .vue ファイルの Lint ということで、当然ですが .vue ファイル内の <script> のみならず、 <template> に対しても Lint が実行され、エラーとなるコードや推奨されないコードを検出してくれることを期待しますが、 <template lang="pug"> のように、Pug で書かれると、パースすることが出来ず、結果として template タグに対して Lint が実行されません。 つまり、プロジェクトの状態としては、 ESLint, eslint-plugin-vue はパッケージとしてインストールされている .vue ファイルに対して ESLint の実行も出来る が、暗黙的に <template lang="pug"> 内は Lint の対象とならず、エラーや警告が検出されない といったものになっていました。 ソースコードのうち一方は Lint され、他方では Lint されないという状態は、開発者がそれ認識した上で”適切に”気を配る必要があるという意味で、Lint がまったく無い状態と同じ、もしくはそれ以上に危ういものと考えました。 (事実、筆者はこのプロジェクトまで Pug を触ったことがなかったこともあり、恥ずかしながら template タグに eslint-plugin-vue が効いていない状態であることに気付いていませんでした。) また、 eslint-plugin-vue を効かせたかった理由として、到来する Vue 3 への準備を進めたかったことも大きいです。 現在、 eslint-plugin-vue のバージョンを next としてインストールし Vue 3 向けのルールを有効化することで、Vue 3 で新しく追加・もしくは廃止される機能やシンタックスに対しての Lint が効くようになります。 あらかじめこの Lint を効かせておくことで、Vue 3 のリリース時に大きな手間をかけずにアップグレードしたいといった狙いがありました。 チームに Pug 推進派がいない プロジェクト黎明期に Pug を推進していたメンバーはすでにチームを離れていたため、現在の開発チームに Pug を推進しているメンバーはおらず、むしろ HTML で書きたいメンバーが存在している状況になっていました。 このような状態は、当然メンバーのモチベーション維持が難しく、また、その技術(今回でいえば Pug)を追っているメンバーがいないことでメンテナンス面で不安が生じます。 (2020/09/04 追記)誤解を与える表現になっていたかもしれないので、念の為補足します。前任の Pug を推進してくれていたメンバーは事業上の理由によって別チームに異動しており、プロジェクト初期にガッツリ貢献してくれたことに感謝こそすれ、負の感情はまったくありません。ありがとうございました!🙏 Pug を HTML に移行するには Pug を HTML に移行するために、AST など静的解析を使って変換するようなツールがないか調べたところ、 vue-pug-to-html というまさに今回の移行にうってつけな変換ツールを発見し、さらにそこから fork する形で、 @plaidev/pug-to-html という変換ツールが公開されていたので、今回はそちらを有り難く利用させて頂きました。 また、利用にあたっては制作者である株式会社プレイド様のテックブログに詳細が記載されており、大変参考になりました。 1,100 超えコンポーネントの Jade / Pug テンプレートを移行した話 | PLAID engineer blog 実際に導入する方法やハマりどころも上記記事にまとめてくださっているので、こちらで再度手順を記載するようなことは行いません。 この場を借りてお礼申し上げます。ありがとうございました! Vue 3 に準拠した Lint ルールを導入する これで Pug がすべて HTML になり、Lint を実行する準備が整いましたが、前述の通り、Lint には Vue 3 に準拠したルールを使用したかったため、以下のリンクに従って導入を進めました。 User Guide | eslint-plugin-vue また、ルールの適用にあたっては、ルールの優先度ごとにまとめたいくつかのルールセットが用意されているので、それらの中から推奨されている vue/vue3-recommended のルールセットを使用しました。 ルールセットの内訳としてはエラーを抑止するための vue/vue3-essential 、可読性を向上させるための vue/vue3-strongly-recommended 、任意の選択と認知的オーバーヘッドの最小化のための vue/vue3-recommended と用意されており、それぞれのルールセットは前の段階のルールセットを包含するような関係にあります。 Lint を実行してみる これで、 template タグに対して Vue 3 に準拠したルールで Lint を実行する準備が整いました。 これまで Lint されていなかった膨大なコンポーネント(約 300 ファイル)に対して一気に Lint をかけるのは怖いですが、勇気を振り絞って実行してみます。 ESLintの実行結果 ...なるほど。ある程度覚悟していたとはいえ、実際の数字を目にすると心にくるものがありますね。 とはいえこれを見て見ぬ振りをするわけにもいかないので、順番に対処していきました。 ここからは、実際に修正していったうえで、特に目ぼしいルールをいくつか紹介していきます。 対応した目ぼしいルール vue-require-v-for-key これは Vue を触ったことがある方であれば一度は目にするようなお馴染みのルールではありますが、今回 template タグに対して初めて Lint が一斉に当たったこともあり、このルール違反が多数検出されました。 対処法としては非常に簡単で、 :key として対象の v-for 内で一意になるような値を設定するだけでよいのですが、今回はまとめてそれを行わなくてはいけなかったことが難点で、特に機能追加などなく長期間触っていなかったようなコンポーネントに対してこの修正をするのは、まず何を v-for で回しているのか、それは直接 :key として設定出来るものなのか、出来なければ、どのプロパティがそれにあたるものなのか(key,id,etc...)を見極める作業が発生してしまい、非常に労力がかかりました。 vue/require-v-for-key | eslint-plugin-vue vue/valid-v-slot v-slot ディレクティブに対して適切な使用法を定めるルールですが、検出数はそれほど多くはなかったものの、これもまた人力を必要とする点で労力がかかりました。 template タグ以外に対して v-slot を使用していた問題 v-slot は本来 template タグ以外のタグに対しての使用は推奨されていないのですが、使用箇所が散見されました。 対処法としては、対象のタグを template タグで囲い、その template タグのディレクティブとして v-slot を記述することが必要になります。 これも前述の vue-require-v-for-key の問題と同じく、 template タグで囲う範囲を見極める手作業が発生するため、手間・難易度ともに高くなりました。 そのほか v-slot は挙動が複雑になりがちなこともあり、 vue/valid-v-slot ルールのなかにもいくつも規則が存在するため、気になられた方は一度以下のリンクをチェックしてみることをおすすめします。 vue/valid-v-slot | eslint-plugin-vue Vue 3 にアップグレードするまで対応出来なかったルール 以下は Vue 3 によって機能追加もしくは廃止されるものに対してのルールになります。 当然準備段階ではバージョンが 2.x なので愚直にこれらのルールの通りに直しても動かないため、これらのルールは .eslintrc.js の rules プロパティにおいて off に指定しました。 準備として Vue 3 用の Lint ルールを先取りして適用したときにのみ発生するような状態なのでこの情報を活用するシーンはあまりないかもしれませんが、備忘としてまとめておきます。 vue/no-deprecated-v-bind-sync 2.x 時代に使えた v-bind:hoge.sync="fuga" といったシンタックスが廃止されたことを Lint するルールで、Vue 3 からは単純に v-bind:hoge="fuga" もしくは :hoge="fuga" とすることで同様の挙動となります。 vue/no-deprecated-v-bind-sync | eslint-plugin-vue vue/no-deprecated-v-on-native-modifier Vue 3 では @keydown.enter.native="onKeydownEnter" のように記述していた .native シンタックスが不要になりました。 vue/no-deprecated-v-on-native-modifier | eslint-plugin-vue 同内容の RFC を見てみるに、 v-on listeners used on a component will fallthrough and be registered as native listeners on the child component root. .native modifier is no longer needed. とのことなので、純粋に .native をつけなくてもよくなった、ということのようです。 rfcs/active-rfcs/0031-attr-fallthrough.md at master · vuejs/rfcs · GitHub vue/no-deprecated-destroyed-lifecycle これはコンポーネントのライフサイクルとして 2.x 時代に存在していた beforeDestroy や destroyed が廃止されたことを Lint するルールです。Vue 3 では代わりに beforeUnmount や unmounted が存在しています。 こちらの RFC はちょっと見つけられなかったのですが、以下のページ中のコードから、おそらく既に存在している beforeMount や mounted とあわせて、mount という単語に集約させたかったのではないかなと推測しました。 vue/no-deprecated-destroyed-lifecycle | eslint-plugin-vue vue/no-deprecated-functional-template Vue 2.x には functional template が存在しているかと思いますが、その廃止を Lint するルールになります。 vue/no-deprecated-functional-template | eslint-plugin-vue 以下の RFC によくまとめられていますが、JavaScript 内で import { h } from 'vue' など DOM を生成するための関数を使用することで同様のことを実現出来るので functional template を使う必要は無い、という意図のようです。 Vue 3 から使用できる(厳密には分離していますが)Composition API にも見られますが、関数に処理を閉じ込めたうえで、コンポーネントでは必要な関数を適宜インポートして使用するだけといった価値観の流れにあるルールなのかなと推察しました。 rfcs/active-rfcs/0007-functional-async-api-change.md at master · vuejs/rfcs · GitHub まとめ 上記のものやその他のルール違反をつぶしていった結果、無事に Lint が通るようになりました! 普段の開発に忙殺されてメンテナンスがつい後手に回るようなことはよくありますが、溜まり溜まった負債を一気に解消しようとするのはやはり体力も精神力も必要と痛感したので、今後はこまめに負債と向き合う機会を意識的に設けていきたいです! 今回の対応のなかで、ここでは紹介しきれない細かな問題(Vuetify の 1 系が Vue 2.6 から導入されたスロットのシンタックスに対応しきれていないこと、などなど。。。)もあったりしたので、話を聞いてみたい方は筆者の Twitter @let_mkt にDMいただけると嬉しいです! また、ここがおかしいなどもあれば上記 Twitter 宛に教えていただけると有り難いです。
アバター
こんにちは!スマートキャンプのエンジニア、瀧川です。 私は今 BOXIL の開発を担当していて、Railsアプリケーションとしてローンチから6年近く経つプロダクトとなります。 その間に溜まった技術的な負債については、タスクの中で併せて解消したり、プロジェクトの合間でまとめて時間をとったりと前向きには取り組んでいる(先日Rails6, Ruby2.7にあげました👏🏻)のですが、どうしても優先度が下がる改善がいくつかあるなと思っています。 今回は改善の優先度が低かったけど、割とストレスに感じていた i18n定義の自動整理 をやってみた話を紹介しようと思います! 地味に苦戦したんですが、結果として 全体の1/3を占めていた未使用のi18n定義を自動削除 することができました! i18n(internationalization)とは 今回やること 解決方法 i18n-tasks ハマったところ i18n定義からHashやArrayで取得している箇所が検知されない 数値キーが文字列キーに変換されてしまう キーの相対パス表現の記述ミス 未使用i18n定義自動削除スクリプト(完成版) まとめ i18n(internationalization)とは i18nとはinternationalizationの略で、日本語だと国際化・多言語化となり、アプリケーションの中の文言を別の言語に切り替える仕組みや定義のことを指します。 流れとしては、クライアントからリクエストがきて、そのリクエストのロケール(言語)が判別されて、ロケール毎定義された辞書ファイルから文言が取得されるようになります。 また別の側面として、表記のゆれをなくし文言の統一をしたり、Enum値(文字の定数)などを管理したりと、そもそもの辞書としてのメリットもあります。 今回やること BOXIL のi18n状況としては、基本的にはアプリケーションコード内に日本語は記述せず、i18n定義をして呼び出すようにしています。 しかし特にルール化されておらず、定義ファイルがいろんな軸で分割されていて、定義の重複があったり、コード修正時に不要になったi18n定義を削除していなかったりと、 実装しているときにどの定義を使えばよいか 判断に迷うことが多々ありました。 そこで今回は、まず 不要なi18n定義を削除 することを目的にしました。 解決方法 アプリケーションの関連する各バージョンは以下の通りです。 ruby(2.7.1) rails(6.0.3.2) rails-i18n (6.0.0) 今回は便利そうな i18n-tasks というGemを見つけたので、以下を導入して自動削除できるようにしました! ただ、本来設定ファイルを置いてやればうまく動いてくれるはずだったのですが、現状のi18nと定義方法や呼び出し方だとうまく動かないところがあり結構ハマりました...。 そのため最終的には、i18n-tasksのAPIを使った、独自のスクリプトを書いて対応しました。 i18n-tasks(0.9.31) i18n-tasks Railsのi18n定義の管理を手助けしてくれるGemです。 具体的には、 「足りていない定義の抽出」「未使用の定義を抽出・削除」「DeepL Proを利用して別ロケールファイルの生成(すごい)」 などが設定ファイルを用意することで自動でできるようになります。 導入方法はリポジトリのReadmeを呼んでいただくのがいいかと思いますが、Gemをインストールして、設定ファイルの雛形をコピーしてくる必要があります。 (RSpecでチェックするための雛形も用意されているので、CIに組み込むのも簡単でいいですね!) echo "gem 'i18n-tasks', '~> 0.9.31'" > Gemfile cp $(i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/ ハマったところ 前述した通り、設定ファイルを配置してコマンドを叩くだけだと、いくつか必要な定義が消えてしまったり、意図していない変更がされたりとハマりどころがあったので紹介します。 i18n定義からHashやArrayで取得している箇所が検知されない あまり良くない使い方かもしれませんが、以下のようなi18n定義のときに、 I18n.t('enums.prefecture') でHashを取得して使っている箇所が多々ありました。 そしてi18n-tasksのunusedを実行すると I18n.t(enums.prefecture.1) など、配下の要素が未使用扱いされてしまいました。 enums : prefecture : 1 : 北海道 2 : 青森県 3 : 岩手県 I18n .t( ' enums.prefecture ' ).each do |key, val| # 例: セレクトボックスの選択肢を生成 end 解決 これについてはi18n-tasksのused(使用している定義)の抽出で、Hash利用時に I18n.t('enums.prefecture') は検出されるため、usedで検出されたパスがプレフィックスにあるキーを削除対象から除くことで回避しました。 スニペット i18n = I18n :: Tasks :: BaseTask .new i18n.data.config = i18n.data.config.merge( sort : false ) unused_tree = i18n.unused_keys( strict : false ) used_keys = i18n.used_tree( strict : false ).key_names.map { |x| " ja. #{ x }" } # 使われているprefixのkeyを削除する unused_tree = unused_tree.subtract_keys(used_keys) 数値キーが文字列キーに変換されてしまう 以下のようなi18n定義が使われているときに、i18n-tasksでremove-unused(未使用定義削除)を実行するとキーが文字列に変換される挙動になりました。 これによって I18n.t('enums.prefecture.1') は問題なく取得できるのですが、 I18n.t('enums.prefecture')[1] はうまく取得できなくなってしまいました...。 enums : prefecture : 1 : 北海道 2 : 青森県 3 : 岩手県 実行後 enums : prefecture : "1" : 北海道 "2" : 青森県 "3" : 岩手県 解決 全然いい方法が思いつかず、筋肉質な解決方法を取りました...。 以下のようにすべてのlocalesファイルでキーが数値にできるのであれば数値に変換し、ファイルを更新する処理を入れました。 そんなに頻繁に実行しないので許されるかな...という気持ちです。 Dir [ Rails .root.join( ' config ' , ' locales ' , ' ** ' , ' *.yml ' ).to_s].each do |file_path| converted_yml = YAML .load_file(file_path).deep_transform_keys do |key| Integer(key) rescue StandardError key end YAML .dump(converted_yml, File .open(file_path, ' w ' )) end キーの相対パス表現の記述ミス 知っている人は知っているrails-i18nの機能で、以下のようにi18n定義がされている場合、対応する app/views/entries/show.html.slim のファイル内であれば I18n.t('.hoge') と I18n.t('entries.show.hoge') が等価になる仕様があります。 これ自体はi18n-tasksでも正しく検出されます。 問題になったのは、実は I18n.t('.hoge') は I18n.t('..hoge') でも I18n.t('...hoge') でも正しく動作するような実装になっているらしく、なぜかプロダクトコード内にそうやって呼び出されているやつらが紛れていたため、i18n-tasksで検出が漏れることとなりました。 (どうしてそうなった...) locales/views/entries ja : entries : show : hoge : hoge 解決 プロダクトコードを修正しました。 そもそもi18n定義をページごと分けてしまうと文言の統一が難しく管理コストが高いため、そんなにメリットがないと思い、基本的に相対パス表記はやめることにしました。 未使用i18n定義自動削除スクリプト(完成版) 完成したスクリプト(Rakeタスクにしました)がこちらになります。 lib/tasks/my_i18n.rake namespace :my_i18n do # `rake my_i18n:remove_unused` task remove_unused : :environment do |_task, _args| i18n = I18n :: Tasks :: BaseTask .new i18n.data.config = i18n.data.config.merge( sort : false ) unused_tree = i18n.unused_keys( strict : false ) # MEMO: t('range.prefecture')のように途中までの指定でHashを取得している場合、unused_keysに'range.prefecture.1'などが検出されてしまう # used_keysでは'range.prefecture'が検出されるため、それを使ってunused_keysからtree自体を削除(subtract)することで必要な定義が削除されるのを回避している # また、t('range.prefecture.#{hoge}')のようにDynamicに値を入れているものはうまく判定してくれないので、gsubでその箇所を除外して判定する used_keys = i18n.used_tree( strict : false ).key_names.map { |x| " ja. #{ x }" .gsub( /\. \# \{.*\}$/ , '' ) } unused_tree = unused_tree.subtract_keys(used_keys) i18n.data.remove_by_key!(unused_tree) # MEMO: t('range.prefecture.1')などのキーが数値のものは、上記の処理で自動で'1'のようにクォートされてしまう # アプリロジックでは数値として使いたいため、以下で無理やりキーを数値に変換している Dir [ Rails .root.join( ' config ' , ' locales ' , ' ** ' , ' *.yml ' ).to_s].each do |file_path| converted_yml = YAML .load_file(file_path).deep_transform_keys do |key| Integer(key) rescue StandardError key end YAML .dump(converted_yml, File .open(file_path, ' w ' )) end end end 一応設定ファイルも抜粋して載せておきます。 そんなに変わったこともないですが、安全でかつコストを掛けすぎないようにしたかったので、excludeとignoreを多めに設定していました。 config/i18n-tasks.yml base_locale : ja data : read : - config/locales/**/%{locale}.yml search : paths : - app exclude : - app/assets/images - app/assets/fonts - app/assets/videos - app/services/hoge_service.rb ## 検査中にエラーが発生するため ## t("categories.#{category}.title")なども検知するため strict : false ## ある程度面倒そうなものはignore ignore : - will_paginate.* - validation.* - simple_form.* - devise.* - activerecord.* - date.* - datetime.* - errors.* - helpers.* - number.* - support.* - time.* まとめ 最近月1くらいでやっている開発改善デーで実施した内容を紹介させていただきました。 (同じ日にこちらも取り組んでいたのでぜひ一読いただければ嬉しいです!) スマートキャンプに入社しました!& Chrome拡張機能をVue.jsで作りました! - SMARTCAMP Engineer Blog 今回i18n-tasksというGemを使わせていただきましたが、とても便利でもっと早く導入してCIに組み込んでいればなぁ...と感じました。 ぜひこれからi18nと向き合っていこうと考えている方は検討してみてください!
アバター
初めまして!8月よりスマートキャンプにエンジニアとして中途入社した吉永です! 私は現在19歳で、通信制の大学に通いながらエンジニアチームの一員として開発に携わっています。 プログラミングは中学生の時に始め、高校在学時にとあるスタートアップ企業でインターンしたり、卒業後はエンジニアとして正社員で開発を行っていました。 得意分野はフロントエンドで、主にVueやNuxtを使った開発が好きですが、前職ではLaravelやDjangoを使ったバックエンドの開発も行っていたため、メンバー構成に左右されない柔軟な開発を行えることが強みだと思っています。 薪入れ作業でChrome拡張機能を開発しました なぜこの拡張機能が必要だったのか どうやって作ったか 主要ファイル解説・作り方 詰まったところ 全体的なまとめ 参考にさせていただいたサイト 薪入れ作業でChrome拡張機能を開発しました スマートキャンプは月一で、普段は機能開発を優先していて手がつけられない、開発チームで解決できる改善課題を行う日を設けています! この日僕らは、開発環境と本番環境を間違えてしまう課題を解決するために、 開発用環境か本番環境かをすぐにわかるようにするChrome拡張機能を作る という課題を設定しました、恐らく見ていただいた方がわかりやすいと思うので、画像を載せると 左上にこれは本番環境ですという文言が出ていることがわかると思います。 なぜこの拡張機能が必要だったのか 「こんなものなくてもURL見れば判別できるじゃん!」と思う方もいると思いますが、STG環境のアプリ内のリンクが一部本番のURLになっているため、STGを触ってるはずがいつの間にか本番を見ているみたいなことが度々あり、それに気が付かずボタンを押してしまうことが多かったのです。 例えば 上の画像はBoxilの資料請求画面ですが、もし開発環境と間違えて本番環境で資料請求をしてしまうと、顧客からの資料請求と認識されてしまい、Boxilの売り上げとなってしまいます。 この場合、他の部署に問い合わせをして、 「今の資料請求間違いです!取り消してください!」 と言わなくてはいけなくなってしまうのです。 そのため、URLを見なかったとしても必ず目に入るような形で本番環境をアピールする必要がありました。 どうやって作ったか Chromeの拡張機能について調べていると、 どうやらVue.jsで作れるらしいという記事 を発見しました。 ディレクトリ構成はこんな感じ 構成自体は至って普通で、VueCLIで作った時とほぼ同じです。 主要ファイル解説・作り方 ・main.js import Vue from "vue" ; import App from "./App.vue" ; ( function () { 'use strict' ; document .querySelector( 'body' ).insertAdjacentHTML( "beforeEnd" , `<div id="app"></div>` ); let vm = new Vue( { render: h => h(App) } ).$mount( "#app" ); } )(); bodyの中にid = appの要素を挿入し、そこにVueをマウントします。 ・App.vue <template> <div class = "test" > HelloWorld ! </div> </template> <script> export default { name: "app" } ; </script> <style scoped> .test { background-color: red; } </style> 今回はテスト用に作った、HelloWorldという文字を画面に表示させるだけのApp.vueにしました。 app以外にもコンポーネントを作りたいという場合は、普段と同じようにcomponentsフォルダの中に.vueのファイルを作り、importしていくといった流れになります。 ・manifest.json { " manifest_version ": 2 , " name ": " BOXILチーム ", " version ": " 0.0.1 ", " description ": " テストコード ", " content_scripts ": [ { " matches ": [ " https://www.google.co.jp/* " ] , " js ": [ " js/app.js " ] } ] , " permissions ": [ " tabs ", " activeTab ", " https://www.google.co.jp/* " ] } googleにアクセスした時にこの拡張機能が動作するように権限の要求だったり、マッチするURLなどを定義します。 ・vue.config.js module.exports = { filenameHashing: false , //ファイル名のハッシュ化防止 productionSourceMap: false , //ソースマップ作成防止 configureWebpack: { optimization: { splitChunks: false //チャンクファイルの生成防止 } , } , publicPath: './' , css: { extract: false //cssを別ファイルに分けずに、一個のjsファイルとして出力させる } } ; ビルドした際に、各ファイルの名前がハッシュ化されてしまうといけないので防止したりしています。 CSSの読み込みなども後々手間なので、一つのjsファイルに出力されるようにしました。 ・package.json //長いので省略 " scripts ": { " build ": " vue-cli-service build src/js/main.js ", " generate ": " npm run build && cp src/manifest.json dist/ && rm dist/index.html " } , //長いので省略 ビルド後にmanifest.jsonをdistフォルダにコピーし、index.htmlを削除しています。 主要ファイルは以上で、npm run generateでdistフォルダに出力します。 その後chromeの拡張機能読み込み画面で、パッケージ化されていない拡張機能を読み込むを選択し distフォルダを選択します。 選択後、 https://www.google.co.jp/ にアクセスすると... このように、HelloWorldが表示されていることがわかります! 詰まったところ URLの内容を見て、本番環境かそうでないかを判別するだけなら簡単でしたが、ページのボタンクリックなども制御しようとした場合に、結局document.querySelectorAllなど素のJSを使ってボタン制御をしなくてはいけませんでした。 そう考えると、「Vueで実装する必要あった...?」みたいな話になってしまいそうですが、面白かったので良しとします。 全体的なまとめ 調べる時間も含めて合計二時間くらいで作成したこの拡張機能ですが、かなり評判もよく、新しい会社に入ってから良いスタートが切れたかなと思っています。 特に一緒にやってくださった徳田さんには感謝です... 本記事が今後Chrome拡張機能を作ってみよう!と思った方の参考になれば幸いです。 参考にさせていただいたサイト 本当にわかりやすくまとめてくださっていてありがたかったです。 r17n.page
アバター
こんにちは!スマートキャンプに21卒入社予定の関口大地です。 私は現在大学に通っている4年生で、法律学を専攻しています。大学では法律学を専攻していますが、在学中に趣味ではじめたプログラミングの楽しさにハマり、Webエンジニアを目指し就活をしていました。 今年の1月にスマートキャンプから内定をいただき、 今年の4月からBOXIL開発チームで内定者としてインターンをしています。 今回のブログでは、内定者インターンとして業務をする中で気がついたことを、紹介していこうと思います。 なぜ内定者インターンをするのか? 内定者インターンを始めてからの気づき 質問できない背景を考えてみた 実際に試してみたこと この経験から学んだこと なぜ内定者インターンをするのか? 私は今年の4月から内定者としてインターンをしています。 私はこの内定者インターンを始めるまで、開発の業務経験はありませんでした。 このインターンを通して、業務としてのチーム開発の手法を学び、新卒で入社したタイミングでしっかりとした戦力になることを目標としています。 これまでに、BOXIL SaaSのトップページに表示されているバナーを管理する機能を実装したり、BOXILのブランドカラーを変更するタスクを担当しました。 Boxil SaaSのトップページに表示されるバナーを設定する機能を実装しました 内定者インターンを始めてからの気づき 初めての業務をするにあたって、悩んだことはたくさんありましたが、なかでも業務中に質問をうまくできないということに悩んでました。 質問する内容は担当しているタスクの実装方法についてのものや、実装を担当する機能の仕様についてです。 テキストベースの質問をうまくすることができずに、 インターンを始めてから2ヶ月ほどはこの悩みを抱えてました。 しかし、この悩みを解決するためにいろいろなことを試行錯誤するにあたって、自分なりの気づきがあったため、お話しさせていただこうと思います。 質問できない背景を考えてみた この悩みを解決するにあたって、まず質問がうまくできない理由について考えてみました。 質問できない背景には リモートワーク中心だったためオフィスなどとは違い、気軽に直接質問することができないこと 自分が質問することで先輩の時間を奪ったら申し訳ないという心理的なものや どのように質問をしたら相手が答えやすいのかという適切な質問の仕方がわからない ということがあります。 実際に試してみたこと テキストコミュニケーションに対して苦手意識があることを、チームの振り返り会でチームメンバーに相談してみました。 その際に質問のやり方を工夫してみたらどうかという助言をいただきました。 具体的には質問をする際に使うツールを変えてみるということです。 機能の仕様の質問、実装方法についての質問など、業務内で何か困ったことや相談事がある場合、私が使うツールはSlackだけでした。 実装方法について質問する場合は、githubを用いてコードベースで質問することが、質問する側もされる側もやりやすいという助言をいただき、試してみました。 作業中のタスクについて、【 WIP 】(work in progress)というタグをつけたプルリクエストを作成し、実装方法について悩んだ箇所にコメントをつけて先輩に質問していきました。 実際にgithub上でコミュニケーションをとることで、お互いコードを見ながら議論を進められ、とても質問しやすいことに気がつきました。 またgithub上で質問することで、実装をする上で考えていたことがログに残り、 後から見返した時にどのような意図でその機能を実装したのかもわかりやすくなることに気がつきました。 この経験から学んだこと このような経験から気がついたことがあります。 それは、質問に限らず、議論する内容によって議論するツールを変えると、議論の効率が上がるということです。 コードベースの実装方法については、githubを使ってコミュニケーションをとることで質問の効率をあげることができました。 リモートワークでの業務をするにあたって大事なことは、このトピックについての相談、質問はこのツールでおこなうという共通認識を持つことだと感じました。 そうすることで自分が質問する上で心理的障壁になっていた気持ちも解消されました。 インターンを始めてから4ヶ月程度たちましたが、ツールを変えることで質問することが難しいという課題を克服し、自分なりの学びもありました。 これからも業務をする上で何かの課題が起きた時にまず仕組みで解決できないかという視点を大切にしていきたいです。 読んでいただきありがとうございました!
アバター
スマートキャンプの20卒エンジニアの高砂です! 皆さんは、JavaScriptにおける絵文字の扱われ方が難しい事をご存知ですか? 本記事では、その背景と適切な方法を解説していきます! JavaScriptにおける絵文字の問題点 問題点の再現 問題点の背景 絵文字を適切に扱う方法 まとめ JavaScriptにおける絵文字の問題点 JavaScriptで文字数カウントを実装する際、素直に考えると下記のようなコードになるかと思います。 const text = 'おはよう😊' console.log(text.length) しかし、実は「絵文字が含まれている文字列は .length では適切にカウントできない」という問題点があるのをご存知でしょうか? 実際にご覧頂くのが早いと思うので、 CodePen 様をお借りして文字数カウントをしてくれるアプリを簡単に作ってみました。 以下に置いておきますので、本記事と併せてご自由にお試しください。 ※ 尚、こちらは後述する方法でのカウントも併せて実装しております。 https://codepen.io/jonpili/pen/bGpbOWJ codepen.io 問題点の再現 このアプリ上で、絵文字が1つ入力された時はこのようにカウントされる事を想定していると思います。 しかし、別の絵文字を入力してみると…なにやらカウントがおかしくなっているようです。 更に他の絵文字にすると、カウントが更に想定より大きくなっています。 ここまで来ると、もはやカウントが意味を成していません。 このようにJavaScriptの .length プロパティは、絵文字によっては想定と違う挙動を示してしまうという問題点があります。 問題点の背景 このようになる理由は、絵文字の多くが通常の文字の2倍以上のbit数で扱われているからです。 JavaScriptでは絵文字も含んだ文字をUTF-16という方式で保存していますが、例えば「お」「は」「よ」「う」のような通常の文字が16bitで表されているのに対し、「😊」は32bitで表されています。 JavaScriptのStringオブジェクトのプロパティである .length では、前者は16bitで1文字分ですが、後者は32bitで2文字分として換算するのでカウントが想定通りに働かないという事になるんですね。 また、「👍🏻」は「👍」に肌の色の定義データを加えて64bit(ベースの絵文字32bit + 定義データ32bit)で4文字分、「👨‍👩‍👧‍👦」は「👨」「👩」「👧」「👦」とそれらを結合するデータから構成されている為に176bit(絵文字32bit × 4 + 結合データ16bit × 3)で11文字分としてカウントされています。 このように絵文字によって様々な理由はありつつも、多くの絵文字は2文字以上でカウントされてしまいます。 絵文字を適切に扱う方法 では、想定通りにカウントするにはどうすれば良いでしょうか? その一番簡単な解決方法は下記のように書くことです。 const text = 'おはよう😊' console.log(Array.from(text).length) これはES2015(ES6)以降で使える記法ですが、このようにすると基本的な絵文字については正しくカウントされるようになります。 [...text].length という短く書ける記法もあるので、そちらでも構いません。 ただこの方法だと、「👍🏻」や「👨‍👩‍👧‍👦」といった特殊な絵文字には対応できません。 それらについても正しくカウントしたい場合、「カーソルが 1 つ移動する分」という定義に基づいてカウントできる下記のようなライブラリを導入するのが良いでしょう。 https://www.npmjs.com/package/graphemesplit まとめ JavaScriptにおける絵文字の扱われ方は複雑で、私も文字数カウントを実装する際は非常に悩みました…。 本記事が、お読みくださる方の開発の一助になれば幸いです。 尚、本記事では絵文字に焦点をあててお話しさせて頂きましたが、実は上記の方法で「𠮷」といった特殊文字のカウントも解決する事が可能です。 というわけで、JavaScriptにおいて文字数のカウントを実装する場合は、本記事でのやり方、もしくは上記ライブラリの導入をおすすめします! それでは、お読みくださりありがとうございました!
アバター
こんにちは、 https://boxil.jp を作っている徳田です。 今回は技術共有ミーティングであるSMARTCAMP Tech Talk、通称「STT」と、Stay Home環境下でのコミュニケーション施策について紹介します。 SMARTCAMP Tech Talkについて はじまった経緯 準備するKibelaのイメージ 数回開催した結果 他: 在宅勤務でのコミュニケーション施策について プロダクト本部 夜会 メンバ間1on1 SMARTCAMP Tech Talkについて  2週間〜1ヶ月ぐらいの頻度で開催される、エンジニア達がそれぞれ興味のある技術ネタを持ち寄って紹介するミーティングです。 用意された Kibela にそれぞれが事前に紹介したい内容を書いておき、それをもとにワイワイ話します。 持ち時間は一人5分程度、ラフなLT大会のようなノリで実施しています。 はじまった経緯 スマートキャンプのエンジニア組織には BOXIL の開発チームと インサイドセールスツールならBALES CLOUD(ベイルズクラウド) の開発チームが分かれており、チーム間の技術的な交流があまり多くありませんでした。 その上、現在は週の4日が基本的に在宅での勤務となっているため、何らかのミーティングが無い限りは顔も見ないといった状況になってしまっています。 それでも問題があるわけではないのですが、隣のチームのメンバがそれぞれがどんな技術トピックに興味があるのか、どんなスキルがあるかを知ると 「このフレームワークは○○さんが詳しそうだから聞いてみようか」とか 「この部分はあのチームが既に似たようなの作っていたからちょっと覗いてみよう」といったことができて便利です。 それを実現するためには技術的な話をするのが一番だろうということで、Tech Talkが始まりました。 同時に、気になっている内容を調べて説明することで理解を深めたり、特定分野に強い人がその方面の説明をすることで、組織全体の技術力向上も一緒に実現しようという目論見もあります。 準備するKibelaのイメージ SMARTCAMP Tech Talk vol.2 での私の内容 最近業務で Web Vitals を改善する活動をしているのでその内容を紹介したり、web.dev LIVEの一部を抜粋して紹介したり、 あとはTwitterで流れてきて便利そうと思ったプロダクトや、考えさせられたブログのエントリを紹介しました。 他メンバはVueのちょっとマイナーな機能紹介や、GraphQL、AWSの新しいプロダクト、コード補完ツールといった内容を話していました。 数回開催した結果 違うチームのメンバが最近気になっていることを知ることはできましたし、同じチームメンバがやっていることを新しく知ることができました。 最終的な目的としている 業務上でのチームを超えたコラボレーション にはまだ至っていませんが、今後何らかの形でできそうだな、という感触があります。 また、個人的な話ですが、 もともと「 #z_news_developers 」という気になった技術情報を共有するSlackチャンネルがあり、技術記事はそこでよく共有されていますが、STTが近づくとその内容を軽く説明できる程度に読み込むようになりました。 今後も続けていこうと考えています。 他: 在宅勤務でのコミュニケーション施策について  STTは「技術的な情報交換」を目的としたものですが、それ以外にもオフィスだとできていた雑談や、ちょっと込み入った話を1:1でするといったことが、在宅勤務がメインになり減ってしまっていました。 それを解決するために行っていることを以下で紹介します。 プロダクト本部 夜会  多くの人が業務を終了する18時45分~19時の間に、「夜会」というミーティングを入れています。 これは業務の話をする場ではなく、"一日の終わりにちょっと近場の人と話すというリアルのコミュニケーションを良い感じに再現する" 取り組みで、Zoomのブレイクアウトルームを使って10分ちょっと雑談をするミーティングです。 在宅勤務だとつい長く働いてしまう人が多いということもあり、一旦仕事の区切りをつける場としても存在しています。 メンバ間1on1 (エンジニアの)1on1は基本的に上長やPdMと定期的に実施していますが、それとは別に同じチームのメンバ同士でも1on1を行うようになりました。 一緒に働いているメンバと雑談はするものの、「改めてこのプロジェクトどうだった?」とか「今これやってるけど実際どうやろか」という形で、一歩引いた状態で話すのは通常業務と切り離して時間を取らないと結構難しかったりします。 チームメンバ同士での1on1ではそういった話を多くしており、今一緒に働いているメンバがどう思っているかを改めて確認できる場として活用しています。 紹介は以上になります。 こういった施策はマネージャ層から提案されたりする他、現場のメンバで提案して、実施したりすることもあります。 みなさんも良さそうと思ったら是非社内で提案したり実施してみてください! また、開発チームに絞った在宅勤務の話は以前ブログに書いたので、是非一緒に読んでもらえると嬉しいです 😌 tech.smartcamp.co.jp
アバター
スマートキャンプ、プロダクトマネージャーの郷田です。 弊社スマートキャンプのセールスチームに、開発チームで行っているKPTによる振り返りを導入してみました。 この記事では実際にKPTを導入するまでの背景と流れ、また実施してみたセールスチームからの感想を紹介いたします。 きっかけ 何ができるか考える やってみた 心理的安全性の説明 リーンコーヒー KPT セールスチームによるKPTの感想 セールスチームに導入してみて まとめ きっかけ ある日に1日かけて、ボードメンバーとセールスチームのマネージャー数名と共に、BALES(自社サービス)の現在のアウトカムの設定・ターゲットの詳細化・仮説の設定などを行うMTGでファシリテーターをさせていただく機会がありました。 ディスカッションの準備から関わらせてもらったため、参加されてた方からは「フレームワークを使いふわっとしたことを整理するのが得意な人」と認識していただき、別の議題について相談していただいたのがKPT導入のきっかけとなりました。 何ができるか考える 今回の相談は、「営業シナリオを考え直したいので、良いフレームワークを教えてほしい」です。 なので、フレームワークとなりそうなものをいくつかピックアップして提案してみましたが、あまりしっくりきません。 私のバックボーンがエンジニアということもあり、セールスチームから言われたことがそのまま本質的に困っていることなのかわかりませんでした。 そこで、30分程度のヒアリングの時間を頂いて、以下のやりたいことがわかってきました。 セールスチームの一人ひとりは十分に活躍しているが、チームとしての成果も最大化していきたい。 営業業務の成果最大化に向けて効果的に取り組めることを探したいため、他部署などの知見を取り入れていきたい。 これらを元に、 「チーム内で課題感を効率的に共有できるようにする」「開発チームで行っているKPTの知見をセールスチームで試してみる」 ことを実施することとしました。 相談内容と要求されてることは違う やってみた セールスチームが集まって話せる時間を2時間頂いたので、時間内で効率的に課題を共有するために 「心理的安全性の説明」 と 「リーンコーヒー」 を実施しました。 また、会の最後に「継続的にKPTをやってみないですか?」と提案をさせていただき、翌日から毎週1時間の 「KPT」 を実施しています。 心理的安全性の説明 数ページのスライドを元に、心理的安全性の説明をしました。 セールスチームの心理的安全性が担保できていないから説明したわけではありません。 チームには心理的安全性という概念が内在していること、またそれがチームパフォーマンスに影響していることを認識してもらうために説明をしました。 心理的安全性の詳細に関しては今回は割愛します。 実際に説明をしてみたところ、強く頷いていただいたタイミングが何度もあり、納得感を持てていただけている様子も伺えたため、この先の振り返りの価値を感じてもらう準備として良い効果を感じました。 心理的安全性のスライド リーンコーヒー 「チーム内で課題感を効率的に共有できるようにする」ためにリーンコーヒーが効果的ではないかと考え、2時間のうち多くの時間を費やし実施しました。 今回リーンコーヒーを選んだ理由としては以下です。 自分の抱える議論したい課題を参加者一人ひとりが洗い出せる 自分と他人のトピックが比較できるため、共通の課題でも役割による視点の違いなどが明確になる 1議論が長くても10分程度で打ち切られるため、その場で出た各トピックについて網羅的に話せる 最初の相談時にいただいた「営業シナリオを考え直したい」という課題もここでトピックとして出されていて、すごく良いことだと感じました。 チームが抱えるすべてのトピックを比較した上で議論したいトピックを全員で決めるため、 チームで一番話すべきことを話せている確証を全員が持てる ためです。 自己組織化が進んだチームほど、他と比較して優先度が高いと思えない限りは「これが課題だ!」と言われても今対応するべきか疑ってしまいがちです。 リーンコーヒーの流れや話した内容の詳細は、BALESのコラムで紹介されていますので、こちらも合わせてご覧ください。 https://bales.smartcamp.co.jp/article/blog-5 bales.smartcamp.co.jp KPT 開発チームは普段スクラム開発を中心としており、1年間継続と改善を繰り返してきています。 「開発チームで行っているKPTの知見が広く通用しうるかセールスチームで試してみる」という意味も含め、セールスチームに対して週1回のKPTの導入を提案し、私がファシリテーションする形で取り入れさせてもらいました。 KPTを選んだ理由としては以下です。 セールスの定例報告ではない、チームパフォーマンスを上げるための振り返りとして使いやすい だれもが理解しやすいフレームワークなので、継続しやすい KPTに関しては説明に利用したスライドを画像で貼っておきます。 心理的安全性の説明とリーンコーヒーを実施した後にKPTを実施したため、参加者もディスカッションに慣れた様子で、 この順番でフレームワークを導入して良かった と感じています。 現在、初回から3週間がたち合計3回KPTを行いましたが、チームパフォーマンス向上という意味での効果は早速出始めているのでは?と感じています。 KPTの説明資料 実際のKPTの様子 セールスチームによるKPTの感想 セールスチームから感想を頂いているので紹介させていただきます。 ・メンバー各自が感じてる課題をアウトプットし共有できるので同じ方向を見て業務ができるようになった ・メンバーの課題や改善点、ネクストアクションをチームで共有することでお互いが意識して指摘できる環境になった ・自分自身とメンバーの共通した課題に気づき、改善の必要性を強く認識できるようになった ・自分にはないマネージャー目線のproblemを知り、全体最適を考えるようになった ・アウトプットの機会が増え、サービスとしての課題等、これまでより視座高く問題を捉えられるようになった ・週1で振り返りの場があることで、小さな気付き(良い点/悪い点)も意識できるようになった ・次週の同じ場でTryの不出来を指摘されないように課題に立ち向かう意識が変わった ・日頃のふわっとした考えを言語化することにより、脳内整理ができるようになってきた ・ネクストアクションが明確になり、まだ数回しか実施してないものの進捗できている感じがする(定量的な成果はまだないですが、、) 感想を読むと、振り返りそのものの良さと、チームによる振り返りの良さが十分に感じてもらえているように思いました。 また、良い感想を頂けてとても嬉しく思っています。 セールスチームに導入してみて 事業運営に携わる人は開発チームに限らず「不確実な世の中」でも「確実な成果」を求められる仕事をしているため、短い期間で振り返りを実施できる文化がチームにあることは、KPTに限らずとても良い効果が期待できると感じました。 私個人としては自分の所属するチーム以外にKPTを導入するのは初めての取り組みではありましたが、一定の効果がありそうだと感じているため今後も継続していきたいと思っています。 この先のセールスチームKPTでは、ソフトウェア開発とセールス現場という特性の違いを認識して、継続していく中でKPT以外のフレームも検討しつつチームにあった振り返りの場に改善していければ良いかなと考えています。 まとめ 今回の紹介は以上になります。 アジャイルな考え方が開発チーム以外にも適用される一例として見ていただき、各社のセールスチームやその他チームにもKPTが導入されるきっかけとなれば幸いです。
アバター
スマートキャンプ、エンジニアの入山です。 突然ですが、みなさんはAmazon ECSを利用したことはありますか? コンテナで開発したアプリケーションをフルマネージドで運用してくれるECSですが、その環境構築を簡単に一括で行ってくれるサービスAWS Copilotが先日発表されました! AWS Copilotでは、ECSの環境構築だけでなく、GitHubと連携したCI/CDの構築もできるようになっており、AWSやCI/CDの知識や知見がなくとも手軽にコンテナでのサービス立ち上げができます。 AWS Copilotを利用したECSの環境構築については、AWS公式のブログで詳しく紹介されていたので、今回はAWS Copilotを使ったGitHubと連携したCI/CDパイプライン構築を中心に紹介したいと思います! aws.amazon.com AWS Copilot とは AWS CopilotでのECS環境構築 AWS CopilotでのCI/CD GitHubへのPushをトリガーとしたCI/CD設定 動作確認 まとめ AWS Copilot とは Amazon ECSでコンテナ化されたアプリケーションの開発、リリース、操作を支援するためのCLIツールです。 AWS Copilotは、単一のコマンドで、タスク定義、イメージリポジトリ、およびロードバランサーやデプロイパイプラインなどの AWS リソースを含め、Amazon ECS および AWS Fargate でサービスを実行するために必要なすべてのインフラストラクチャとアーティファクトを作成します。( 公式サイト から引用) つまり、何も存在しないAWS環境上に、VPCやサブネットなどの基礎的なリソースやECS運用に必要なリソースなどを全て作成し、手元に用意したDockerfileに従ったアプリケーションのイメージビルド、ECS上へのデプロイ、更にはLBを作成して外部公開する所まで、何から何まで自動でやってくれる便利ツールです。 AWS CopilotでのECS環境構築 AWS Copilotでは、 copilot init を実行し、対話形式に以下の情報を入力するだけで、Amazon ECSを運用するために必要な全てのリソースが自動で作成されます。 デプロイするアプリケーションの名前 アプリケーションのサービスタイプ デプロイするコンテナのDockerfile この記事では、Copilotのセットアップや copilot init の詳細については、割愛します。 冒頭で紹介したAWSの公式ブログに詳しく紹介されているので、そちらを参考にしていただければと思います! AWS CopilotでのCI/CD AWS Copilotは、ECS実行環境の構築だけでなく、CI/CDの構築も簡単に行うことができます。 現時点で、以下構成のCI/CDパイプラインを構築することができます。 GitHubの設定したブランチへのPushをhookし、AWS CodePipeline上のパイプラインを実行 AWS CodeBuildでGitHubからPullしたソースコードをビルドし、イメージをAmazon ECRのリポジトリへPush PushされたイメージをAmazon ECS(Fargate)にデプロイ CodeBuildの設定やCodePipelineの設定は、Copilotによってマニフェストファイルが自動生成された後にカスタマイズ可能なので、柔軟にビルド仕様やデプロイフローを設定することもできそうです。 また、デプロイ先の環境(test、productionなど)も設定することができるようになっているため、異なる環境の構築も簡単に行なうことができます。 GitHubへのPushをトリガーとしたCI/CD設定 GitHubリポジトリのmasterブランチへのPushをトリガーに、自動でCI/CDが実行されるように設定していきます。 ECS環境の構築と同様に、以下のコマンド1つでCI/CDパイプラインの設定ができます。 $ copilot pipeline init こちらも対話形式で、以下の項目を設定していきます。 CI/CDの対象とする環境の種別(複数環境へのデプロイや順序も指定可能) GitHubのリポジトリ GitHubへのPushをhookするためのアクセストークン GitHubのアクセストークンは、 repo と admin:repo_hook の権限が必要となります。 以下を参考に設定します。 docs.github.com 上記項目の入力が完了すると、CodeBuildとCodePipelineのマニフェストファイルが自動生成され、GitHubへのPushをトリガーとしたCI/CDパイプラインの構築が完了します。 実際にコマンドを実行したログが以下になるのですが、これだけでCI/CDが構築出来てしまうのでかなり衝撃的です…! 動作確認 GitHubリポジトリのmasterブランチに変更をPushして、実際に実行されたCI/CDパイプラインが以下となります。 GitHubへのPushをトリガーに以下の3つのステージが実行され、ECSへ新しいバージョンのアプリケーションがデプロイされています! GitHubからソースコードのPull DockerイメージのBuild ECSへのデプロイ まとめ 今回は、AWS Copilotを利用して、ECSの環境構築とGitHubをトリガーとしたCI/CDパイプラインの構築を紹介しました。 環境構築とCI/CDの構築を合わせても、たった2コマンドの10分程でECS上でのサービス起動まで出来てしまう衝撃的なサービスですが、将来的には更にS3バケットやデータベース、ストレージのセットアップなども出来るようになるようです! AWS Copilotを使うことで、ローカルのDockerで開発したプロトタイプなどを誰でも簡単にECS上に立ち上げることが可能になるので、上手く運用することで様々な用途で利用できそうです。みなさんも是非一度試してみてください!
アバター
こんにちは。プロダクト本部で本部長(開発に関わる部署のマネージャー的な役割)をしている米元です。 弊社では昨年から技術顧問としてヨシオリさんに参画して頂いております。 今回はヨシオリさんにこれまでどんな形で関わって頂いたのか、スマートキャンプがどのように見えるのかを話して頂きました。 ​ 最初に自己紹介をお願いします! 技術顧問を始められた背景を教えてください 試行回数を増やしたい 視野を広げたい 技術顧問として開発チームとどんな関わり方をしていただいていますか? スマートキャンプ開発チームの印象はいかがでしょうか? 全体的な印象 良いところ 改善点/足りない点 スマートキャンプで活躍できそうなはどんな人でしょうか 開発チームへの今後の期待をお願いします! まとめ 最初に自己紹介をお願いします! 庄司嘉織といいます。 インターネット上でも twitter.com/yoshiori とか yoshiori (Yoshiori SHOJI) · GitHub とかだいたい本名をつかって活動してます。 今は Launchable, Inc. というアメリカのスタートアップで働いています。Jenkins の川口さんが立ち上げた会社って言ったほうが通りが良いかもしれません。 前職までは日本の Web 企業とか SI とか色々経験しています。 エンジニアとしてはサーバサイドに軸足を置いています。分散システムとかマイクロサービスとかそういった話も大好きですね。 www.wantedly.com 技術顧問を始められた背景を教えてください そうですね。その話をする前に前提として僕は技術顧問としてめっちゃ尖った技術について専門家として相談にのるというパターンではなく、エンジニア組織の課題の相談やどういった方向を目指すのかという相談にのるというのをメインにしています。 なので、なぜそういったスタンスでやろうと思ったのかを説明しようと思います。 試行回数を増やしたい 1 つ目は試行回数を増やしたいという思いがありました。エンジニア組織を作るというのはなかなか 1 人の人間が何回も経験できるものでは無いと思います。 幸運にも僕は何度か経験させてもらっていますが、そうじゃないことのほうが多いと思います。 そう考えると「何度か経験させてもらっている」という僕の経験は良い武器だと言うことになります。そしてその武器をもっと伸ばすにはどうすればいいかを考えた時、試行回数を増やすのが最良だと思ったのでその方法として始めたというのがあります。 視野を広げたい もう 1 つは視野を広げたかったという思いです。前職で長い期間エンジニア組織について考えていたのですが、どんどん新しい考えが浮かびにくくなるんですよね。最初の 2 年くらいはどんどんインパクトのある施策とか考えられるんですが繰り返していくとなんというか細かいものしか思い浮かばなくなっていました。 前職は好きだったので辞めるつもりはない。でも視野を広げるためにほかも見てみたいと考えました。 逆にエンジニア組織を立ち上げてまだ間もない会社ではエンジニア組織を立ち上げたことがある人を求めているのは知っていました。そういった会社に自分の経験や知識をつかって技術顧問をするというのはお互いにとって良いなと感じたので始めたかんじです。 技術顧問として開発チームとどんな関わり方をしていただいていますか? 基本的には 1 週間に 1 回の米元さんとのディスカッションがメインです。 米元さんからの相談に対して私の経験を元に壁打ちする形式で、今後どのような組織を作っていくかや、そのために必要な評価制度や採用などの方針について話していきました。 また、最近だとWith/Afterコロナでの制度や働き方、リモートワークで今後発生する課題についてもディスカッションをしました。 他にはプロダクトチームからの相談に乗ることもあります。実際のアプリケーションの設計の相談やリファクタリングどう進めるか、新しい機能の設計の相談などです。必要であればもっと専門的な相談にのれる僕の知人を紹介したりもします。 僕が他でやってみてよかった手法などを紹介したりすることもあります。Design Doc は僕が友人に教わってからすごく気に入って自分自身も考えを整理するときに使っているのでそのへんの知見も含めて共有したりしました。あと何回か提案として僕の方から Design Doc を書いたりしましたね。また最近だとリモートでの意思決定の方法として現職で教えてもらった DACI フレームワークを紹介したりもしました。 www.atlassian.com 現場のエンジニアのみなさんとの 1on1 も時々やっています。最初に僕が 1on1 で何を目的にしているのかをドキュメント化してそこからやっています。最近はコロナのせいで出来なくなってしまいましたが、お昼を食べに行ったりしてました。代わりにいまは夜のリモート飲み会に参加させてもらったりもしてます。 スマートキャンプ開発チームの印象はいかがでしょうか? 全体的な印象 最初の印象は若く良い人が多いなと思いましたね。 今まで経験してきた B2B 系のサービスとかではまれに「俺は自社サービスにはそこまで興味ないんだぜ」というスタンスがカッコいいと思っている人とか斜に構えている系の人とかがいたのですがそういった人が 1 人も居ないことに驚きました。 すごくちゃんと人をみて採用しているんだなと感じました。 メンバーは若くて良い人が多いです 良いところ メンバーについて 先程も書きましたが良い人が多いのがすごく良いですね。 たぶんリーナスとかの影響が大きいと思うのですが、優れたエンジニアは人格が若干攻撃的で良いと考えている人をたまに見かけます。 何故か攻撃的になればエンジニアとして成長できると勘違いしている人ですね。僕の見た範囲での話になってしまいますがエンジニアとして凄い成長する人は素直で人の話もちゃんと聞く人がほとんどです。 そういった意味でエンジニアとしての良い素質を持っている人が多いという印象です。 チーム全体について みんな積極的に自分のサービスを良くしようと思っていますし、新しい技術的にチャレンジするのも楽しんでいます。 そういった個々の気持ちがチーム内にも良い空気を作っているように見えます。 会社やチームのフェーズについて 会社としては一つの軸となるサービスが出来て新しいサービスも動き始めているという成長期の楽しいフェーズだと思います。 規模的にもまだ経営層の方々との距離も近いし個人の力の影響力も出せるしチームとしての馬力も出せるサイズ感だと思いますね。 改善点/足りない点 若いチームだからというのもありますが、一歩ひいて先をみれるひとが少ないところですかね。 何かするときにみんなで一丸となっていくのは良いことなのですが、一歩離れた視点やもう 1 歩先を考える人がもう少し増えるとバランスが良くなるかなと思っています。 スマートキャンプで活躍できそうなはどんな人でしょうか そうですね、私の印象だと以下に当てはまるような人だとスマートキャンプで活躍できそうだなと思ってます。 個の力を大事にしつつもチームの成果を喜べる 問題をそのまま解決するのではなく問題の本質を見極めて解決出来る これらを人から与えられて動くのではなく自分ごとにして動ける 開発チームへの今後の期待をお願いします! こんな状況になってしまってもみんな前向きですごく良いと思います。 いま世界が変わっていっている中でも前向きにどうやったらチームやサービスが良くなるかを考えて進んで行けているのは今後絶対に大きいアドバンテージとして効いてくると思います。 まだまだドンドン大きくなっていく組織だと思っていますし、サービスも大きくなっていくと思っています。そのお手伝いができると僕も嬉しいですね。 ​ まとめ 私自身はどうしても目の前の作業に時間も頭のリソースも専有されがちだったのですが、定期的にヨシオリさんと話をする時間を持つことで 開発組織だけでなく会社全体についても中長期の視点で考えるタイミングが作れる 一段上の視座で物事を見ることが出来る ようになりました。 おかげで開発組織の方針決めや中長期の未来に向けての施策を進められるようになってきました。 また、以前はマネジメントをするうえでの課題や悩みについて1人で悶々とすることが多かったのですが、ヨシオリさんと壁打ちさせてもらうことでそれらの整理ができるようになった事は個人的に大きく、ありがたいなと感じています。 開発組織のメンバーもヨシオリさんのように経験のある方と相談する機会を持つ事で刺激になっているようですし、知り合いのエンジニアを紹介して頂いて爆速で開発を進められるようになったりと個人としても組織としても助かっています。 このように技術顧問の方からもサポートしてもらえる環境に興味がある方は、ぜひ以下から応募してください! hrmos.co
アバター
ボクシルのプロダクトマネージャーをしている笹原です。 今年頭からエンジニアではなくプロダクトマネージャーに業務内容をシフトしています。 しかし、エンジニアブログは技術ネタを書こうかと思い、表題の件をサクッと試してみました。 AWS Client VPNとは AWS Client VPNのクライアント認証とユーザー管理 AWS SSOとは AWS SSOでのカスタムSAML2.0アプリケーションの追加 SAML2.0認証を利用したAWS Client VPNエンドポイントの作成 実際に使ってみる まとめ AWS Client VPNとは AWS Client VPNとは、AWSが提供しているクライアントベースのマネージドVPNサービスです。 マネージドなVPNサービスということでリモートワークが増えた今年から利用も増えているのではないかと思います。 詳しく知りたい方は、以下の記事を御覧ください! tech.smartcamp.co.jp AWS Client VPNのクライアント認証とユーザー管理 このサービスでのクライアント認証は2パターン用意されていました。 Active Directoryを用いた認証 個々のユーザーに証明書を発行しての相互認証 そんな中、第3の認証方式としてAWS Client VPNがSAML認証のサポートを開始したというリリースが出てきました! SAML認証が可能ということであれば、ユーザー管理をSAMLベースのIDプロバイダー(IdP)側に持たせることが可能になり、何かしら特定のSSOサービスなどを使っている場合にユーザー管理を一元化できます。 aws.amazon.com 実際に使ってみようと思ってドキュメントを見てみると、テストされたSAMLベースのIdP設定リソースは現在はOktaのみでした。 テストされているSAMLベースのIdPの表 残念ながら会社ではOktaを利用していないので、他のIdPを使えないかと試してみたのがAWS SSOです。 AWS SSOとは AWS SSOとは、『複数のAWS アカウントやビジネスアプリケーションへのSSOアクセスを簡単に集中管理できる』と謳われているSingle Sign-Onサービスです。 2017年にリリースされているサービスですが、東京リージョンにはまだ来てません。 上記の通り、AWSアカウント以外の一般的なクラウドアプリケーションへのSSOアクセスも可能で、SAML2.0認証を用いたカスタムアプリケーションの設定も可能です。 ということで、早速試していきましょう! AWS SSOでのカスタムSAML2.0アプリケーションの追加 AWS SSOを開始するにあたっての設定はドキュメントに記載されている以上のことはしていないので割愛し、AWS SSOを利用している状態から始めていきます。 AWS Single Sign-On とは - AWS Single Sign-On まず、AWS SSOのコンソールを開きます。 まず、 新規アプリケーションの追加 ボタンを押します。 アプリケーションカタログから接続するアプリケーションを選択する画面になりますが、 まだAWS SSOがAWS Client VPNのService Provider設定を登録していないようなのでカスタムSAML2.0アプリケーションの追加ボタンを押します。 この画面で入力する必要があるのはアプリケーションのメタデータです。 AWS Client VPNのドキュメントに記載されているサービスプロバイダー情報を入力します。 アプリケーション ACS URL: http://127.0.0.1:35001 アプリケーション SAML 対象者: urn:amazon:webservices:clientvpn 認証 - AWS Client VPN また、後ほどAWS Client VPNの設定をする際に利用するのでAWS SSO SAML メタデータファイルも落としておきます。 最後に以下の通りにサービスプロバイダーであるAWS Client VPNに連携されるSAMLアサーションの属性マッピングを行います。 アプリケーションのユーザー属性 マッピング 形式 Subject ${user:subject} emailAddress NameID ${user:email} basic 上記が実際に試した際に動作した最小構成ですが、AWS Client VPNのドキュメントを見ると以下も必須と記載されています。 FirstName LastName memberOf 最後に割当ユーザータブからAWS Client VPNを利用できるユーザーを割り当てたら、AWS SSO側のカスタムSAML2.0アプリケーションの追加設定は完了です! SAML2.0認証を利用したAWS Client VPNエンドポイントの作成 次にAWS Client VPNの設定をしていきます。 その前に下準備として、先程落としたAWS SSOのSAML メタデータファイルをIAMから登録しおきます。 プロバイダの作成 ボタンを押します。 プロバイダーのタイプはSAMLを選択し、プロバイダ名はわかりやすい自由な名前を入力し、メタデータドキュメントを選択して作成します。 以上ができたら、下準備は完了です。AWS Client VPNエンドポイントを作成していきましょう! 既存の通常の作成フローと異なるのは認証情報の設定欄のみです。 認証オプションをユーザーベースの認証を使用を選択し、そのうち統合認証を選択します。 SAML プロバイダーARNを選択することになりますが、これは、先程IAMから登録した際に作成されたリソースを選択しましょう。 他の部分は通常の手順通りで作成することができます!! 実際に使ってみる 実際に利用する際に必要なのは以下の3つです。 AWS SSOからAWS Client VPNの利用を割り当てられたユーザー AWSが提供する専用クライアント こちらからダウンロード: AWS Client VPN Download | Amazon Web Services AWS Client VPNのクライアント設定 AWS Client VPNのコンソールからダウンロード それでは利用していきましょう。 まず、AWSが提供する専用クライアントを起動します。 メッセージの言われるがまま、[ファイル] > [プロファイルを管理]を押します。 プロファイル管理モーダルが開かれるのでプロファイルを追加していきます。 VPN設定ファイルはAWS Client VPNのコンソールからダウンロードしたクライアント設定ファイルを選択します。 最初のモーダルに戻ると接続準備完了となっているので接続すると、ブラウザが開いてログイン画面が表示されます。 AWS Client VPNの利用を割り当てられたAWWS SSOのユーザーでログインします。 ログインが成功すると上記のメッセージが表示されます。 AWSが提供する専用クライアントに戻ると接続済みとなり、これでVPNの接続が完了しました! まとめ 今回はAWS SSOをIdPとしてAWS Client VPNをSAML認証で利用してみました。 VPNはリモートワークは進んだ中で利用が加速したサービスだと思うので、 そこに対して機能が追加されユーザーに選択肢が増えるのは嬉しいことですね。 現在はOktaのみがテストされたIdPとなっており、かつ、私が試した限りだと、 GSuiteはACS URLがhttpだとカスタムアプリケーションができなかったりとまだ制限もありそうですが、これからの開発に期待です!
アバター
こんにちは、スマートキャンプでBiscuetを開発している井上です。 今回はSendGridでメール配信をするときにやったこと、知っておきたいことなどをまとめてみました! SendGridとは? SendGridでメールを配信する理由 メールに必要な機能が充実している 送信実績 日本語ドキュメントの充実感 料金プランについて検討する 共有IPと固定IPの違い 共有IPの場合 固定IPの場合 共有IPと固定IPでの作業の違い IPを育てる なぜ, IPを育てる必要があるのか? レピュテーションとは? IPウォームアップ とは? IPウォームアップのやり方 レピュテーションを維持するための宛先のクリーニング 宛先のクリーニングとは? 宛先のクリーニング対応方法 SendGrid側でやってくれる対応 オプトアウトの対応をする オプトアウトとは? SendGridのオプトアウト機能 メールイベントログを取得できるようにする メールイベントログで知れること メールイベントログのインフラ構成 最後に SendGridとは? sendgrid.kke.co.jp SendGridは全世界で利用されているメール配信サービスです。 月間600億通以上の配信実績があり、メール配信するにあたって必要な機能を提供してくれます。 SendGridでメールを配信する理由 様々なメールサービスがある中で、SendGridを選ぶ理由は以下の通りです。 メールに必要な機能が充実している メールに関する基本的な機能が一通りそろっており、機能がなく困ることはほとんどありません。 主な機能 オプトアウト機能 カスタムドメインの設定 メールの開封チェック機能 迷惑メール・バウンスの管理 送信実績 メール配信システムを選ぶ際、どのくらいの送信実績があるかは、メールを送信した際の到達率や、送信したメールが迷惑メールに入ってしまうか否か、などに影響するため大事なポイントです。 日本語ドキュメントの充実感 メールのような低レイヤーな技術を扱うサービスにおいて、トラブル時の対応や設定周りのドキュメントがまとまっていることはとても助かります。 実際に自分もわからないことだらけだったのでこの辺りはかなり助けられました ! 料金プランについて検討する 価格 | SendGrid SendGridのページにプラン料金の表がありますが、その表を見た際に送信上限以外にそこまで違いが無いように見えます。 大きな違いはメールを送信するにあたって共有IPと固定IPのどちらを使用するかで、これにより初期の工数が大きく変わります。 共有IPと固定IPの違い Freeプランは共有IPで、Proでは固定IPが割り振られるという違いがあります。 どちらも送信時に送信元で使用されるIPです。 このIPの信頼性の高さによってメールが受信者に到達するかが左右されます! 共有IPの場合 メールを配信する際、共有IPでは他のユーザと共通でIPアドレスを使用することになります。 そのため、他のユーザーのメール配信の影響を受ける可能性があります。 固定IPの場合 メールを配信する際、使用する自分たちの専用IPアドレスになり、他のユーザーの影響を受けることはありません。 共有IPと固定IPでの作業の違い 大きく違う点としては IPを育てる必要があるか否か という点です。 作業としては一つですが、これにより工数が大きく変わってきます。 IPを育てる なぜ, IPを育てる必要があるのか? 送信元IPの信頼性によってメールが受信拒否になるなど不利益を被る可能性があり、それを防ぐためです。 そのためにはメールの レピュテーション を上げる必要があります。 固定IPの場合はレピュテーションがゼロからスタートするので、育てる必要があります。 レピュテーションとは? ISPなどが評価する指標のことです。 これは、メール送信側が信頼あるメールシステムなのか?というのをISPなどの第三者が判定しているもので、具体例でいうとGoogleやMicrosoftなどが評価者になります。 この指標が低いと受信拒否やスパム判定をされることがあり、 送信実績や迷惑メール対策をちゃんとしているかなどで評価が決まってきます。 ただ、ISPごとに評価基準が異なるようなので、完璧に対策するというよりはマイナス要素を減らしていくのを頑張る、というイメージです。 詳しくはこちらの記事が参考になります。 qiita.com IPウォームアップ とは? 大量のメールを送信するには、送信実績を積み、レピュテーションを上げる必要があります。 そのため、段階的にメールの送信量を増やしていき、送信実績を作りあげることでレピュテーションを上げるのがIPウォームアップです。 IPウォームアップのやり方 実在のメールアドレスに送信する 実在のメールアドレスに送らないとIPウォームアップにならないためです。 コンテンツはちゃんとしたものにする コンテンツの内容も、迷惑メールになるかどうかの指標の1つになります。 送信数は徐々に増やす 送信数はIPの信頼性をあげないとメールがユーザーに到達しない可能性があります。 実際に送信数をどのくらいのペースで増やせばいいのかは、SendGridの出しているスケジュール例が参考になりました。 https://sendgrid.com/docs/assets/IPWarmupSchedule.pdf レピュテーションを維持するための宛先のクリーニング レピュテーションはスパムや受信拒否などが発生するとで下がります。 そして、SendGrid内でもレピュテーションの参考数値を持っており、一定まで下がるとアカウント停止の恐れがあるとのことなので、しっかり対応することをおすすめします。 宛先のクリーニングとは? 送ってはいけない・送ることができない宛先にメールを送らないように除外することです。 宛先のクリーニング対応方法 私たちのチームではKickboxというサービスを使用して宛先クリーニングを行うことにしました。 kickbox.com UI上からクリーニングしたいメールアドレス一覧のCSVをuploadすることでクリーニング結果が返ってきます。 また、クリーニング結果の理由など詳細についてもある程度知ることが出来ます。 無料で100件まではクリーニングできるので、一度試してみてもいいかと思います。 SendGrid側でやってくれる対応 また、SendGridが自動でレピュテーション維持のために下記のようなことを行っています。 迷惑メール報告があった宛先にはメールを送らない 存在しない宛先にはメールを送らない 配信停止機能で配信を希望しないユーザーにメールを送らない SendGridの画面上のReport機能でどのくらい迷惑メール報告されたかなども確認できます。 オプトアウトの対応をする オプトアウトとは? 受信者がメールを受け取りたくない場合に配信停止をする機能のことです。 特定電子メール法にも記載されています。 SendGridのオプトアウト機能 SendGridでもオプトアウトの機能があり、タグを埋め込むことでオプトアウトが可能です。 作成したグループごとにオプトアウトをすることも可能で、キャンペーンごとのオプトアウト対応といった作業も可能になります。 sendgrid.kke.co.jp メールイベントログを取得できるようにする メール配信後、メールの到達・開封・クリック率を見たいといったことがあると思います。 SendGridでは画面上でイベントログのダウンロードなどはできず、後から過去のイベントを取得することも出来ないため、SendGrid側が提供しているEvent WebHook機能を利用してメールのイベントを取得することをおすすめします。 メールイベントログで知れること SendGridでは下記のようなことをイベントとして取得してくれます! 迷惑メールになってるか メールが送られているか メールが開封されたか メール内のリンクがクリックされたか また、カスタム情報をメールに追加できるので、自社のDBの情報とメール情報を紐付けることも可能です。 メールイベントログのインフラ構成 メール1通に対して2~3イベントほどが発生するため、ある程度大量にメールを送る場合、かなりのRequestに耐えられる構成にする必要があります。 具体的なインフラ構成や設定は以下を参考にしました。 sendgrid.kke.co.jp 最後に 今回は自分たちで事前に知っておきたかったSendGridでメール配信するまでの内容を書いてみました。 この対応で全て網羅できるわけではないですが、少しでも参考になれば幸いです!
アバター
こんにちは!スマートキャンプでエンジニアをしている中川です。 先日Twitterを何気なく眺めていたところ、Vue.js 生みの親の Evan You氏が何やら興味深いツイートをしているのが目に止まりました。 As I was going to bed, I had an idea about a no-bundler dev setup (using native browser ES imports), but with support for Vue SFCs **with hot reload**. Now it's almost 6AM and I have PoC working. The hot reload is so fast it's near instant. — Evan You (@youyuxi) 2020年4月20日 ...なるほど。これまでReactやVueを用いたフロントエンドの開発環境はWebpackに代表されるbundlerを通すことがデファクトとなっていますが、初回起動の時間が長い・HMRにラグが発生するなどの問題はあったかと思います。 導入はどうやるんだろう、実際どのくらい早くなるんだろう、など疑問が湧いてきたので、今回の記事では実際にViteを使ってみます! 余談ですが、Viteの発音は ばいと ではなく ゔぃーと らしく、リポジトリにもその記載がありました。(ばいとばいと言ってました...) https://github.com/vitejs/vite#trivia 導入 ディレクトリ構成 機能 TypeScript 本番環境のビルド React, Preact 対応 まとめ 導入 では早速Viteをローカルで導入してみます! 基本的にリポジトリの Getting Started に従って進めていきます。 github.com 以下コマンドを実行します。 $ npm init vite-app <project-name> $ cd <project-name> $ npm install 手順に従って実行していきます インストールが終わったようなので package.json を確認してみます。 { " name ": " try-out-vite ", " version ": " 0.0.0 ", " scripts ": { " dev ": " vite ", " build ": " vite build " } , " dependencies ": { " vue ": " ^3.0.0-beta.14 " } , " devDependencies ": { " vite ": " ^0.20.0 ", " @vue/compiler-sfc ": " ^3.0.0-beta.14 " } } scripts には開発サーバ起動のための dev コマンドと本番環境のファイルをビルドする build コマンドを持つのみ、 依存関係は vue, vite, @vue/compliler-sfc のみと、非常にスッキリした構造になっています。 また、vueのバージョンは3が指定されているため、Composition APIなどVue 3の機能をデフォルトで使用することが可能です。 Vue 3に関しては以前記事を投稿したので、よろしければ併せてお読み下さい。 tech.smartcamp.co.jp では問題なく起動出来るか確認してみます。 $ npm run dev 起動の様子 無事起動確認出来ました。 実際に npm run dev 実行から上記のログが表示されるまでは1秒かかっておらず、フロントエンドの開発サーバ起動時間としてはまさに爆速と言えそうです。 vue-next-webpack-preview cold server start: 1909ms / compiled for first view: 2732ms vite cold server start: 129ms — Evan You (@youyuxi) 2020年5月4日 最後に http://localhost:3000/ にアクセスしブラウザの表示も確認してみます。 ブラウザの表示も確認 問題なさそうですね。 コンソールにはvite上のイベントが出力されており、HMR対象のファイル、例えば HelloWorld.vue を変更し保存すると、コンソールに [vite] /src/components/HelloWorld.vue reloaded. といった変更を検知したファイル名とともに表示がされます。 ディレクトリ構成 ディレクトリ構成は以下です。 $ tree -a -I "\.DS_Store|\.git|\.gitignore|node_modules" . ├── index.html ├── package-lock.json ├── package.json ├── public │   └── favicon.ico └── src ├── App.vue ├── assets │   └── logo.png ├── components │   └── HelloWorld.vue ├── index.css └── main.js 4 directories, 9 files 実際に表示されるHTMLの流れとしては以下のような形でした。 index.html 内で /src/main.js を module タイプの script タグとして読み込む さらに /src/main.js で /src/App.vue を createApp し、 index.html の <div id="#app"></div> にマウントする /src/App.vue から子コンポーネント等をインポートする 機能 ここからはドキュメントを読んでいて気になった機能を紹介します。 TypeScript TypeScriptのサポートは以下のような仕様のようです。 .tsファイルと <script lang="ts"> 形式インポートのどちらもサポート .tsファイルはトランスパイルを行う .tsファイルと.vueファイルのどちらも型チェックは行わない IDEやビルドプロセスで型チェックを行う前提 esbuildを使って .js にトランスパイルするが、tsc の20~30倍の速度 HMRの更新は50ms以下でブラウザに反映 esbuildは前述の通りトランスパイルのみ行うので、TypeScript の特定の機能をサポートしない tsconfig.json の compilerOptions で "insolatedModules": true を設定することで警告する 本番環境のビルド ES Modules の import はウォーターフォール的なネットワークリクエスト下においてページロード時間がかかりすぎるため、Vite はビルド機能を有しています。 シンプルにビルドするには vite build を実行するだけですが、内部的にはRollupを使用しているため、挙動をカスタマイズしたいときはRollupの対応したオプションを vite build に渡すことで実現できます。また、Rollup由来でないオプションも提供しているようです。 https://github.com/vitejs/vite/blob/master/src/node/build/index.ts React, Preact 対応 この記事中では Vue を使用してきましたが、あくまでもデフォルトの選択肢というだけで、Vite は React や Preact にも対応しています。 viteプロジェクト作成時に、 $ npm init vite-app の代わりに $ npm init vite-app --template react など、 --template オプションに対して react もしくは preact を指定することでそれぞれのライブラリに対応する形で初期化されるようです。 また、jsxにも対応しており、リポジトリ内に詳細な手順がありました。 https://github.com/vitejs/vite#jsx-with-reactpreact まとめ 駆け足で紹介してきました。 フロントエンド開発サーバの起動やHMRの待ち時間がなくなったことで開発体験として非常にスムーズになり、普段の開発で意外と待ち時間に対してストレスを感じていたことを実感出来たのも発見でした。 リポジトリにも Still experimental, but we intend to make it suitable for production. とある通り、今すぐプロダクトに導入出来うるものではありませんが、Evan氏が精力的に開発し続けていることもあり日の目を見る日は近いのかなと思いました。 今回の記事は以上になります、それでは!
アバター
スマートキャンプ、エンジニアの瀧川です。 弊社では毎週火曜日に30分間、エンジニア全体MTGがあり、全体やチームの動き、採用やイベントについて話すようにしています。 その中に「最近のワイ」というコーナーがあります。 (こちらに詳細が書いてあります) YWTで振り返るエンジニアリングマネージャーになってからの1年間 - SMARTCAMP Engineer Blog これは直近の数ヶ月で、「やったこと」「はまったこと」「わかったこと」「次やること」を振り返り、共有する試みで、弊社エンジニアの伝統となっています。 今週が私の担当だったのですが、失念していて準備を忘れるというインシデントが発生したため、反省の意を込めてブログで公開させていただきます。 「最近のワイ」自体はとてもいい試みなので、参考にしていただければ幸いですし、弊社の雰囲気も感じていただければと思います! 最近のワイ やったこと 子供が生まれる(1/14) 育休に入る(2/1~3/1) 育休明け急遽BiscuetチームからBOXILチームへの異動(3/1~) 既存(若干)闇プロジェクトへのジョイン(3/1~4/18) 新規プロジェクトの推進(4/18~現在) はまったこと 育児 仕事 わかったこと 育児 仕事 次やること 育児 仕事 まとめ 最近のワイ 前回の「最近のワイ」が2019/12/12だったので6ヶ月間と長めになっています! (本来は2ヶ月に1回程度だけどタイミングが合わず...) やったこと まず大きいトピックとしては以下かなと思います。 子供が生まれる(1/14) 育休に入る(2/1~3/1) 育休明け急遽BiscuetチームからBOXILチームへの異動(3/1~) 既存(若干)闇プロジェクトへのジョイン(3/1~4/18) 新規プロジェクトの推進(4/18~現在) 子供が生まれる(1/14) なんといってもこれですね。 1/14に第一子の息子が誕生しました!(2876g, 46.8cm) 生まれたてで鼻が潰れている子 予定日が1/17だったんですが、1/13の夜テレビを見ていたら破水して、その14時間後には生まれてきてくれました。 陣痛始まってから生まれるまでの時間が2時間と、分かる人には分かると思いますが異常に早く、妻が信じられないくらいつらそうで、廊下で待っていたあの2時間は絶対に忘れないと思います。 (耐えきって生んでくれた妻には本当に尊敬と感謝しかないです) 育休に入る(2/1~3/1) 2月中は会社・チームの理解の元、1ヶ月の育休を取らせていただきました!感謝! 育休はとって良かったな...と感じています。 最初の一ヶ月は本当にしんどくて...親の仇と言わんばかりに泣き続けていましたね 基本的にはシフト制で、自分が深夜帯、妻が朝から昼みたいに分担していました。 (分担しないと体力的にやっていけないけど、ひとり泣く息子を深夜にあやすのはかなり寂しく不安になりましたね) Biscuetの開発も大事なところではあったんですが(Biscuetという新規プロダクトのテックリード的な立場だった)、各メンバーがもりもりオーナーシップ発揮して機能開発してくれているのをSlackでみて心強く感じていました。 (当時の様子はこちらの記事にあります) tech.smartcamp.co.jp 技術方向だと1ヶ月間で合間を見つけてはTypeScriptの本を呼んで、しっかりと読み切ることはできたし、簡単なアプリケーション開発くらいはする時間がありました。 (常々眠かったけどスキマ時間はあった) book.mynavi.jp 育休明け急遽BiscuetチームからBOXILチームへの異動(3/1~) 3月復帰したら作らないといけない機能たくさんだな...と思いながら育休を過ごす中で米元さん(EngineeringManager)からチーム異動の相談があり、育休からの復帰と同時にBiscuet(新規プロダクト)からBOXIL(既存プロダクト)への異動が決まりました。 異動の経緯は色々ありますが、自分に期待されていること(チームの活性化、開発スピード上げる)が明確だったので、快く受けました。 とはいえ、Biscuetへのモチベーション(やり残したこともある)や、BOXILに対する不安(レガシーな開発をあまりしていない、ステークホルダーが多い)など気持ち的には多少モヤモヤはありました。 既存(若干)闇プロジェクトへのジョイン(3/1~4/18) 職場復帰と同時期にコロナの影響で全社的にフルリモートでの業務に切り替わり、育児&職場復帰&異動&闇プロジェクト&フルリモートというカオスが極まった3月が始まりました。 闇プロジェクトとはなにかというと、BOXILの売上のコアな箇所の改修で、最もレガシーで最もセンシティブな箇所ということですでに開始から数ヶ月暗中模索しているプロジェクトでした。 4月入った(異動から1ヶ月)くらいから自分とチームの関わり方、開発の勘所がつかめてきて、なんとか4/18にリリースすることができました。 新規プロジェクトの推進(4/18~現在) 前闇プロジェクトから今まで、新機能の開発をしていました。 新機能はほぼスクラッチの実装で、SEOなども関わらない場所だったので、Vue.js+TypeScript+RailsのSPA構成で作ることとしました。 ここからはタスクの進め方、技術、リモートについてかなりなれてきていたので、かなりスムーズに開発できているかなと思います。 やっと与えられた責務(チームの活性化、開発スピード上げる)を果たせてきたかなと思います。 はまったこと 育児 育児は最初の1ヶ月が本当にしんどかったですが、はまったということもなく、あ!これがあの本に書いてあったやつか!みたいな発見が面白かったです。 (最近だと首がすわるってこういうことなんだ...って感動しました) 仕事 育休中考えていたのは、自分が育休とってからチームが活性化した部分も多く、嬉しい反面チームにいたときからもっとうまく働きかけできなかったのかとは思いました。 復帰後でいうと、正直3月中はあまりパフォーマンス出せなかったのは辛かったなと思ってます。 チームとの距離感や技術キャッチアップはやはり時間はかかりました... わかったこと 育児 育休明けからのフルリモートがかなりよかったです。 さっと仕事の合間にお風呂入れたりおむつ替えたり、妻が買い物いくときに横目で見ておくとか、出社前提だとできなかったことが多かったなぁと思います。 先輩ぱぱに、1歳過ぎてたりすると保育園が休みになったし夫婦でリモートワークだししんどい...みたいなことを聞きましたが、うちは妻も育休中で保育園もまだだったのでちょうど助かったなと感じています。(これから保育園関係どうなるかは心配ですが) 仕事!育児!をきっちりとやった数ヶ月で、かなり濃密な時間でした。 仕事 弊社のエンジニア組織だと初めてのチーム異動だったのですが、意外となんとかなりましたし、良い効果も多かったかなと思います。 モチベーションなど心配なことはありましたが、チームメンバーの熱い思いとか期待感とかもあり、今では前にも増してプロダクトや組織に良い影響を与えたいと思っています。 しかしながらやはり、1ヶ月くらいはどうやってもなかなかパフォーマンスはでないなーとは思いました (採用時などはオンボーディングなどよく考えていたけど、チーム間異動でも必要そう) また前チームが自分離れて活性化したとこもあり、チームマネジメントとか接し方ではまだまだ課題があるなと思いました。 次やること 育児 育児の軸だと、もうすぐハイハイしそうだったり、離乳食がはじまるので、妻と協力しつつ楽しみたいと思っています。 そろそろ過酷な保育園関連のタスクが入ってくるので、気を引き締めていきたいです。 あと、コロナが落ち着き次第、祖父母やらに子を見せにいきたいですねー 仕事 これからさらにチームが大きくなる(増員する)ので、チーム構成や今までやってきたスクラムをどうしていくか、自分はどういった立場でなにをやっていくかをより俯瞰して考えていきたいです。 (よくスペシャリストっぽいって思われるけど、自分としてはジェネラリストでマネジメントとか興味ある、もっと勉強しないとなー) 半年後にプロダクトに対し、継続的にインパクトを残せるチームになっていると嬉しいなと思います。 まとめ 特にオチもないですが、いかがでしたでしょうか!?(個人ブログでやれと言われそうですがw) 実際にエンジニア全体でこれをやってみると、プロジェクトや組織に対するエモい話だったり、技術に対する知見だとか、新しい趣味だとか色んな情報がオープンになり、活発なコミュニケーションのきっかけになっていると感じています。 昨今のリモートワーク導入で、目に見えないモチベーションだとかチームワーク、一体感みたいなものが少し希薄になりがちですが、それを改善する一つの方法なのかなと思います。 みなさんもわいわいしてみてはいかがでしょうか? ありがとうございました!
アバター
皆さんこんにちは! 21卒の内定者として現在BOXIL開発チームでインターンをしている関口です! 私は今年の4月からスマートキャンプでインターンをしていますが、このインターンを始めるまで、業務としてプロダクトを開発したことはありませんでした。 業務としてプロダクトを開発するようになってから、自分が今まで使ってこなかった開発手法、技術、サービスがたくさんあるということを知りました。 今回のブログでは特に最近勉強になったBOXILの運用を支える監視ツールについて紹介していきたいと思います。 監視をおこなう理由 BOXILで利用している監視ツールについて Mackerelとは Bugsnagとは New Relicとは 最後に 監視をおこなう理由 そもそもなぜ監視をおこなう必要があるのでしょうか? 監視をおこなう理由を一言で表すなら 「システムを安定して稼働させ、稼働効率を上げるため」です。 アプリケーションを運用していると予期せぬ障害やエラーが起きます。 (あまり起こって欲しくはないですが、、) そのエラーがなぜ起こり、どこで起きているかを把握するために必要なものが監視ということになります。 またアプリケーションのパフォーマンスを計測するためにも監視ツールは使われます。 以前のブログで長期休暇中の監視当番について取り上げている記事があるのでぜひご覧ください。 tech.smartcamp.co.jp BOXILで利用している監視ツールについて 続いて実際にBOXILチームで使われている監視ツールについて紹介していきます。 私たちのチームでは主にMackerel、New Relic, Bugsnagの 3つのサービスを監視ツールとして利用しています。 それぞれのサービスの概要、チーム内での運用方法をご紹介していきます。 Mackerelとは mackerel とは株式会社はてなが運営しているアプリケーションサーバーなどのリソース状況を監視するためのサービスです。 mackerelを日本語に直すと魚のサバを表します。サーバー→ サバ→ Mackerel ということが名前の由来らしいです。 各リソースの状況をグラフで表示してくれるため、どのリソースに対して問題が起こっているのか直感的に把握することができます。 私たちのチームでは毎日の朝会でメンバー全員でMackerelを見ながらアプリケーションサーバーのHTTP Response timeやredisのcacheの接続などについて問題がないかを確認しています。 Bugsnagとは Bugsnagとはエラー検知のために用いられる監視ツールです。 MicrosoftやAirbnb、GitHubなど全世界5000を超える 開発組織 で使われています。 BugsnagをRailsのアプリケーションやRedisに埋め込むことによって、 アプリケーションのどこでどのようなエラーが起きてしまっているのかを瞬時に観測することができます。 BOXILチームではBugsnagとSlackを連携させ、エラーが起きた際にSlackに通知を飛ばしすぐに誰でも確認ができるようにしています。 BugsnagをSlackと連携 Bugsnagやmackerelは約2年前から私たちのチームで使われており、当時のチームの課題であったアプリケーションの安定性を向上させるために導入されました。 tech.smartcamp.co.jp New Relicとは 続いてアプリケーションのパフォーマンスを監視するツールをご紹介します。 私たちのチームではNew Relicというサービスをパフォーマンス監視ツールとして利用しています。 New Relicを用いることでアプリケーション全体のレスポンスタイムや、アプリケーションのactionごとのスループット(一定時間にどれくらいの仕事を処理できるか)を計測することができます。 これによりどの処理が原因でアプリケーションのパフォーマンスを低下させているのかを見つけることができます。 以前のブログでパフォーマンスの改善するためのポイントについて紹介しており、その中でNew Relicについても取り上げているのでぜひご覧ください! tech.smartcamp.co.jp 最後に 今回の記事では監視をおこなう理由、BOXILで使われている監視ツールについてご紹介させていただきました。 それぞれの監視ツールを利用することでBOXILを日々安定して運用することができています。 個人開発ではあまり使われない監視ツールですが、大量のトラフィックがあるプロダクトを運用する際にはとても役に立つことをインターンを通して知りました。 今回のブログは以上です。読んでいただきありがとうございました!
アバター
スマートキャンプの20卒エンジニアの高砂です! 新卒入社後、スマートキャンプでは2週間の全体研修と1ヶ月のエンジニア研修に参加しました。 本記事では、後者のエンジニア研修について紹介させて頂きます! 研修目的 「一定以上のレベルで実務に貢献できる技術力」を身につけること OJTではない分、目指すレベルは高く 研修内容 1ヶ月でAsanaを再現 実際の開発結果 研修による成長 Vue.jsでの開発に自信が持てるように 質問・相談の質が向上 研修を踏まえて今後どうするか 習得した技術を中心に事業へ貢献 質問・相談はより具体的に その機能の将来を考えて設計・開発 最後に 宣伝 研修目的 「一定以上のレベルで実務に貢献できる技術力」を身につけること ベンチャーでは「OJTで学んでいく」というのも一般的です。 しかし私の場合は先輩社員と相談した結果、研修中はメンタリングをして貰いながら実務とは直結しない個人開発で技術を学び、研修後に実務に貢献できるようにじっくり成長する事にしました。 それによって、実務に用いる技術を網羅的に学ぶのが狙いです。 OJTではない分、目指すレベルは高く OJTとは違って実務に貢献できない分、目標とするレベルは高く置く事にしました。 具体的には、 タスクを渡されたらすぐに実装イメージが思いつく状態 書いた内容は自信を持って説明できる状態 の2点を達成するのを目標としました。 研修内容 1ヶ月でAsanaを再現 私の配属先ではフロントエンドにVue.jsを用いています。 今回の研修ではそこに強みを持って貢献できるよう、幅広くフロントエンド開発が行えるテーマとしてAsanaのクローンアプリを採用しました。 asana.com 具体的には、このサービスのリスト画面(メイン機能であるタスク管理画面)をフロントエンドのみ再現していく開発内容です。 Asanaのイメージ画像 このような複雑なUIの設計/開発を通して、Vue.jsで出来る事を増やすのが狙いです。 実際の開発結果 結果、1ヶ月の開発でタスク管理ツール「jinli(チンリー)」が完成しました。 jinliのイメージ画像 デモサイトとしてデプロイもしてあるので、是非ご覧ください。 jinli-app.herokuapp.com 研修による成長 Vue.jsでの開発に自信が持てるように 入社前もVue.jsでの開発経験自体はありましたが、「触った事があるので調べればなんとか開発できる」程度でした。 その為、自信を持って開発が出来た事はほとんどありませんでした…。 しかし、研修後はたくさんの機能開発を通じて「すぐに実装イメージが思いつき、開発後は動く仕組みを説明できる」というようになれました! Vue.jsでの開発も少し自信を持て、積極的に実務に貢献しようと思えるようになれました。 質問・相談の質が向上 また副次的な効果として、研修中の先輩社員への質問・相談を通じてその質が向上しました。 具体的には、質問・相談の目的が明確になり、その為に必要な情報の事前共有およびその具体性を高められるようになれました。 自分も先輩社員も時間が限られている中で、いかに効率的に教わっていくかという事を意識した結果、質問・相談の質を向上させられました。 研修を踏まえて今後どうするか 習得した技術を中心に事業へ貢献 まずは研修の本来の目的である「実務への貢献」を目指し、Vue.jsを中心に自分の技術力を最大限発揮していこうと思います。 質問・相談はより具体的に また今後も周りから教わって成長していくにあたって、質問・相談の質をより向上する事は必須だと考えました。 その為、その具体性をより高めて相手に伝わりやすいように共有する事を意識します。 その機能の将来を考えて設計・開発 そして研修中に上手く出来なかった事としては、これが挙げられます。 例えば「この実装で動くからこれでいいや」と安易に設計/開発した後、「あの時こういうデータ構造にしていれば良かった…」という後悔を何度かしてしまっていました。 なので今欲しい機能だけではなく、「将来的にこういう機能が欲しくなるだろう」という予測も頭に思い浮かべながら、それに適切な設計・開発を選択していくという事を出来るようになろうと思いました! 最後に 以上が、私が1ヶ月のエンジニア研修で行い、学んだ事となります。 本記事がエンジニアを志している学生や、新卒研修を検討しているエンジニア、そしてスマートキャンプを興味を持ってくださっている全ての方の参考になれば幸いです😊 宣伝 【バックエンドエンジニア】〜テクノロジーで社会の非効率を無くす!プロダクトの成長にコミットいただける方を募集!〜【フレックス・週1リモート】 | スマートキャンプ株式会社
アバター
こんにちは、BOXILの開発をしている徳田( @haze_it_ac ) です。 今回は業務と少し離れた話をしてみます。 はじめに みなさんは仕事以外でもWebアプリケーションを作っていますか? 作りまくっている人も、仕事以外ではコードを書かない人も居るかと思います。 私は気になったライブラリを見つけたり、こういう実装ってできないかな?と思った際に、簡単なWebアプリケーションを作って試しています。 この記事ではその中で、ゴールデンウィーク中に "簡単に作れて、運用が楽な SPA/SSR + API Server 構成の小さなWebサービス" を考えて試した際の構成と、作成手順を紹介します。 サンプル 画面 https://blog-sample-fe.now.sh/ 見た目が雑で申し訳ないのですが、サンプルとして 会員登録 ログイン 会員ページ ログアウト 機能を実装したものです。 構成 全体の構成 フロントエンドはNext.jsを、バックエンドはRuby on Railsを使いました。 デプロイ先はそれぞれVercel, Herokuを選択。 GitHubリポジトリのstaging, productionブランチの変更をフックに、staging環境やProduction環境にdeployされます。(サンプルのリポジトリ上ではProduction Deployのみを行っています) ローカルではRuby on Rails, DB等をdocker上で、Next.jsはMacOS上で動かして開発します。 VercelとHeroku Vercel vercel.com VercelはZEIT社が提供する、フロントエンド向けのホスティングサービスです。 All-in-one を謳っており、Global CDNが付いていたり、Serverless Functionsを作れたり、Preview機能が付いていたり、LighthouseやGoogle CloudとのIntegration機能があったりと、本当に様々な機能が存在します。 Zero Config というだけありセットアップがかなり簡単で、特にZEIT社がメインで開発しているNext.jsとセットで使用するとめちゃくちゃ簡単にSPA/SSR/SSGのWebフロントエンドを作ることができます。 Heroku heroku.com HerokuはSalesforce社が提供する、 "インフラ管理が不要な" PaaSです。 長く続く人気のあるサービスなのでご存知の方も多いと思いますが、正式にNode.js, Ruby, Java, Python等に対応しており、様々なアプリケーションをデプロイすることができます。 大きな特徴は、CNCFにも追加されたBuildpacksという仕組みで、Linux上で走ることのできるアプリケーションであれば何でも動かせることです。この仕組みを利用し、DB、ジョブスケジューラ、監視Agent、webサーバなどを簡単に提供することができます。 選定理由とメリット どちらもインフラレイヤを考えることなく、アプリケーション開発に集中するためのプラットフォームです。 インフラレイヤで何かを試したい(kubernetesで遊びたいとか)のであれば選択肢からは外れますが、私はアプリケーションレイヤのことを考えていることが多く、これらを選びました。 また、どちらもGitHubへのpush, 特定branchの変更をフックに自動でデプロイができる仕組みが標準で用意されており、デプロイ時のワークフローもあまり考えなくて済むことも大きな理由です。 アーキテクチャ以外の話 DB JawsDB MySQL | Heroku Dev Center Heroku上のDBはJawsDB MySQLを使っています。 Herokuの環境変数にDBのアクセス情報を設定するのを忘れないようにしましょう。 認証方式 jwt.io 認証はJWTを用いて行いました。tokenはCookieに保存しています。 ruby-jwtで簡単に実装できます。 [application_controller.rb] # JWT def jwt_encode (user_id) expores_in = 1 .week.from_now.to_i preload = { user_id : user_id, exp : expores_in } JWT .encode(preload, ENV [ ' SECRET_KEY ' ], ' HS256 ' ) end private def jwt_decode (token) decoded_token = JWT .decode(token, ENV [ ' SECRET_KEY ' ], true , { algorithm : ' HS256 ' }) end https://github.com/haze-it/blog-sample-be/blob/master/app/controllers/application_controller.rb#L30-L41 エラーが出た時のトラブルシューティング、tipsなど ログ Herokuは heroku logs --tails --app [アプリケーション名] でログを見ることができます。 (GUIの画面でも多少見れますが、数十行しか見れないのでCLIをおすすめします) Vercel CLI Overview | CLI Commands | Vercel Docs Vercel上のログも vercel logs ... で見れるようです。 Herokuからの返事が遅いとき 無料プランでのHerokuはしばらくリクエストが来ない状態が続くとワーカーを落とすようで、次にリクエストが来た際に立ち上げ直して処理をするといったことをします。 そのため最初の一回目のアクセスだけレスポンスが遅くなります。 有料プラン(Hobby以上)にすると、24時間立ち上がり続けるようになるため、ちゃんとサービスを運営する場合は少しお金を掛けたほうが良さそうです。 devcenter.heroku.com また、Herokuのサーバは24時間ごとに一度再起動を行い、リリース等をしています。 複数台構成にすればかぶらないようになるそう。ミッションクリティカルなシステムを構築する際は注意したほうが良さそうです。 vercel.com Vercelに関しては、チーム開発をする場合や追加の機能を使いたい場合、SLAが欲しいといった場合は有料になりますが、個人で使うぶんは無料です。 以上が作ったものの紹介とtipsになります。 今回紹介したサンプルのソースコードは以下のリポジトリに置いています。 github.com github.com 次にやること 一般的なWebアプリケーションではほぼほぼ必要となる非同期処理、メール送信、他APIとの連携機能などを作ることで、一通りのアプリケーション開発の素振りをしようと思っています。 AWSのSQSやLambda, SESを使って楽に実装していけたらなと考えています。 真面目に外に公開できる程度のちゃんとしたアプリケーションもそろそろ作らないとな...とも...思っています...やっていきます...🙃 (エラー対応、監視、セキュリティ対策(CORS,XSS対策)などもやらないといけないですね... 紹介した構成だと、アクセスが跳ねたらDBがボトルネックになって死にそうなのでそこもどうにかしたいですね。 最後に いかがでしたか? たまに普段と違う技術を使ってみると気分転換になったり、仕事だと得られない経験が得られることもあります。 ぜひ皆さんも試して遊んでみてください!
アバター