TECH PLAY

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

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

226

スマートキャンプでBALES CLOUDというSaaSを開発をしている井上です。社内では師匠と呼ばれています。 BALES CLOUDはスクラムで開発をしているのですが、自分達のスクラムイベントは同期的な動きが求められるようなイベントが多くありました。 タスクの難易度によってはスクラムイベント + 突発的な相談MTGで開発時間が削られて開発が進まないなどの課題もでてきていました。 そこで現在は非同期でドキュメントを元に会議や議論をする形に一部を移行する取り組みをしております。 なので今回はどのような考えでこの活動をしたかや、得たものや失ったものについて共有できればと思います。 前提 非同期を考えた理由 当時のMTGについて 目指した状態 何を非同期にするか? 実際にやった非同期の活動 実際に運用した朝会記事の構成 チームの休み・フレックスカレンダー Try確認 タスク進捗確認 相談内容チェック POレビュー日・リリース日の調整 ディスカバリーバックログ その他共有事項 記事の確認チェック 非同期化の失敗 問題1: 朝会内容の想定誤り 問題2: 必要な情報が集められていなかった 問題3: 緊急性と発散する内容のコミュニケーション 非同期で得たものと失ったもの 非同期で得たもの 非同期で失ったもの 失ったものへのアクション 感想 今後 前提 同期と非同期の考え方 同期と非同期のコミュニケーションは以下のように分けて考えています。 同期:同じ時間を共有したコミュニケーション(例:MTG、1on1) 非同期:異なる時間でのコミュニケーション(例:Slack、メール) どちらも良し悪しがあるため、チームとの相性を見つつ生産性を高める方法を取ることができればそれで良いと考えてみます。 記事内で伝えたいこと この記事を通じて自分達と同様に同期のコミュニケーションしかしていなかった人たちが 非同期という活動をする際に少しでも参考になればなと考えています。 そのため、これが最高の働き方だ!という話をするわけではなく自分達にとって良かったことや悪かったことを伝えていきます。 記事内でふれないこと この記事に置いて生産性という言葉を多く使いますが、どのようにして生産性を計測しているかは それだけで大きなテーマなのでここでは話しません。 ※ そのうちFour Keysの取り組みなどご紹介する記事で話していきたいと思います。 非同期を考えた理由 開発チームで議論すべきテーマや問題が多かった時期に1週間のスケジュールのほとんどがMTGなっている時期もありました。 チームとしては必要なMTGと考え取り組んでいましたが、開発時間もとりたいとも思っていました。 この解決手段がなにか無いかと考えたときに技術顧問のよしおり(@yoshiori)さんからLaunchableの働き方を教えていただき、自分達なりに一部の要素を取り入れられないか?と考えました。 https://speakerdeck.com/yoshiori/enziniaringu-x-us-hai-wai-tofalsekoraboresiyon 当時のMTGについて スクラムイベントの固定されたMTGや相談や仕様詰めの時間1on1などもあり、多い週だと1週間で下記のようにMTGが発生している状態でした。 リファインメント: 3時間 朝会(デイリースクラム): 1.5時間(30分×5) スプリントレビュー: 1時間 スプリントプランニング: 2時間 レトロスペクティブ: 1時間 突発的なMTG: 2時間 横断的なチームビルディング: 1時間 1on1: 1時間(30分×2) 合計で12.5時間程MTGをしており、稼働時間のおよそ3割はMTGをしている状態でした。 目指した状態 理想としてはチームビルディングや1on1など関係性を向上するMTGや障害などの緊急対応以外は非同期に移行していける状態を作ることでした。 これは同期が必要なMTG以外はドキュメントで完結することと書くという文化を根付かせたいと考えました。 自分も過去に開発しているなかでMTGでの会話で意思決定したものが多くあり、口頭だけで文章としてはどこにも残っていない状態でした。 今から考えると、MTGをせずともドキュメントでの確認で済む内容もあったかと思います。 このようなことをなくしていく意味でも、ドキュメントを書く文化があれば、決定の背景などを今の人が知ることができたなと感じていました。 そのような考えから、ドキュメントを書くという文化の醸成を目指したというのもあります。 何を非同期にするか? これはとても悩みました。 悩んだ中でやったのは非同期にしてはいけないMTGを考えました。 ブレストなどの考えを発散するMTG 障害対応などの緊急性が高いMTG 1on1やチームビルディングなどの時間を共有するのが大事なMTG これ以外を考えたとときに良さそうかなと考えたのが朝会の非同期化でした。 朝会は、報告・共有がメインであることから、非同期化するには適していると考えました。報告や共有は議論が発生せず、定型的なやり取りで済むことが多いためです。ただ、相談などのやり取りが発生する会話も朝会で行っていたので、そのあたりは非同期化する際の課題となりそうでしたが、むしろ非同期化の課題として向き合うには程よいレベルのものだと考え直しました。 実際にやった非同期の活動 まずは行なう理由や目指す状態、最初の取り組むべき点をチーム全体に共有し、自分主導で進めました。 そのなかで実際にやったことの一部をご紹介します。 Notionを使う 非同期をやるうえでとても重要だったのがNotionを活用することでした。 ドキュメントでコミュニケーションを取るうえでドキュメントの書きやすさ・読みやすさに加えてコメントや質問をしやすいかはとても重要でした。 そのなかでNotionは書きやすく、Databaseなどを上手く使えば情報の集約や整理などもしやすくリアルタイムでの同時編集も可能なのでドキュメントで会話するのにとても合っていました。 AsanaからNotionへのタスク移行 今まではAsanaでタスクの管理をしていましたが、Notionうえでコミュニケーションを取るうえでも情報はできる限りNotionに集める必要がありました。 そのためにAsanaからNotionへのタスク移行しました。 幸いNotionはimport機能があったので必要なタスクだけ移行するのはそこまで手間になりませんでした。 朝会記事の作成と運用ルールの作成 朝会を非同期化するために、朝会の内容を書き込む「朝会記事」を作成しました。 この記事では、メンバーが日々の報告や連絡を書き込んで、朝会の内容を共有します。 具体的な朝会記事の運用ルールとしては以下のようなルールにしました。 朝会開始時刻の10:00~には報告・相談内容を書き終えてる状態にする 12:00までには記事の確認を終えてチェックボックスに✓をつける 相談内容があればメンション付きでコメントする 定期的に振り返リの設定 非同期での共有は慣れておらず課題が多く出る可能性があるため、チームとしてはできる限り早く変化に適応する必要がありました。 そのため1週間で課題の収集や改善の実施を行なうことで多くの改善をしていきました。 具体的に実施した改善は以下の通りです。 相談がしにくいので相談ルールを決める 予定の把握がしにくいのでカレンダードキュメント内に追加する Sprintアイテムが見にくいので記事に埋め込む 朝会で確認していた前SprintからのTry(KPTで出た改善内容)を確認する場がなくなり、忘れがちなので記事内の目に付く場所におく 今回の朝会の非同期化を通じて、自分達が朝会という場で多くの確認や共有をしていたことがよくわかりました。 実際に運用した朝会記事の構成 チームの休み・フレックスカレンダー チームメンバーの休みやフレックス予定がGoogleカレンダーと言ったり来たりだったので、記事上にカレンダーを作成して確認可能にしました。 Try確認 チームが課題を改善していくうえでレトロスペクティブで設定したTryの実施は重要だと考えています。 ただ、非同期になると朝会で確認していたTryを確認しなくなり、Tryを忘れる問題が起こってしまいました。 このためTryをしっかりNotionのDatabaseで管理し記事に埋め込むことで、自然と確認できるようにしました。 これによりTry実施のオーナーが不在の場合などもチームで気づいて実施するような動きができるようになりました。 タスク進捗確認 スプリントのタスク一覧を表示してそれぞれ進捗や詳細を記載していく場所です。 タスクもNotion Databaseで管理しており、今スプリントのタスクを表示しています。 メンバーはこれらのタスクの細かい進捗や状況のみを共有してチームの認識をあわせました。 相談内容チェック 記事のなかでどこに相談をかけばいいかや、相談内容を見落とすことなどがあったので相談専用の場所を作成しました。 相談内容はNotion Databaseで管理しており、チームが相談事があると投稿して記事内に表示されるようになっています。 こちらも完了した相談内容は表示されません。 POレビュー日・リリース日の調整 スプリントのタスクのなかでPO Review日・リリース日に該当するアイテムを表示しています。 BALES CLOUDチームではPO Reviewとリリース日の目標日をPlanningで設定するようにしており そこを過ぎたものは調整するために使用しています。 ディスカバリーバックログ PM側の企画の進捗状況を報告します。 エンジニア側でもPMの動きを知ることでお互いがサポートできる状態を作っていくためにこのような場所を設けています。 その他共有事項 タスク以外で採用関連だったり、社員共通の連絡事項を共有したりします。 記事の確認チェック 非同期では誰が記事を確認し終えてるかがわからないため記事を読んで確認したらチェックを入れてもらうようにしました。 これにより誰が読み終えてるかがわかるようになりました。 非同期化の失敗 非同期化はすべて上手く言ったわけではありませんでした。 そのなかで失敗した事例を一部ご紹介します。 問題1: 朝会内容の想定誤り 朝会での当時の想定は左の内容で動き出しましたが現実は右のようにやることがかなり多くありました。 これらを整理するために書き込む場所を分けたり一部をNotionのDatabaseを作成しそちらに移行したりなどを行い解決していきました。 問題2: 必要な情報が集められていなかった 朝会では想定以上の共有事項があったことがわかりましたが これらの情報を同期のときはただ話すだけではなく共通の画面などを見ながら話していました。 これは全員が同じ情報を取得していると考えると、これを補わないとそれぞれが上手く情報を取得してくることを強いることになり、情報量の差でコミュニケーションの齟齬が発生していました。 これの解決のために朝会のDocにそれぞれの休みやフレックスを記載するカレンダーやSprintのタスクなどをNotionのDDatabaseからとってきて表示するようにしました。 問題3: 緊急性と発散する内容のコミュニケーション ドキュメント内の会話のなかで緊急性が高いまたは発散する内容のコミュニケーションの場合はすぐに返答が欲しいときなどがありました。 このようなときは別途Slackするのかなどのルールが決まっていなかったので動きにくいとの意見がありました。 この問題から緊急度と会話の発散性によってNotionに書くだけやNotionに書いたうえでSlackするなど 用途によって使い分けるようにし、その時のルールとして下記の図のように対応することに決めました。 非同期で得たものと失ったもの 非同期の活動の一部をご紹介しましたがすべてが良かったわけではなく 得たものと失ったものがありました。 どちらもやらなければ気づけいない部分もあり、振り返ると挑戦して良かったなと感じています。 また、失ったものと書いていますが別の形で解決する手段もあるというのがとてもいい気づきでした。 非同期で得たもの 時間 これは明示的に朝会分の時間増えたことにより、チーム全員が動きやすかったり考える時間ができました。 個人的にも時間ができることにより余裕をもって作業を進めることができるようになりました。 考える間 ドキュメントで非同期でやりとりすることによりリアルタイム性は失われましたが 1つ1つの確認事項や相談事項に対してしっかり考えて回答できるようになりました。 対面だとその場で答えなければなりませんが、非同期であれば少し調べたりなどしてゆっくり回答ができるようになるのは良い点でした。 情報整理力 非同期のためにはNotionを使用してのドキュメント文化を作る必要がありましたが、その際に前提となる情報や背景をしっかり書くことが求められたのでこれらは自分たちが何を気にしていて最低限どんな情報があれば進めるかを定義できたいい内容でした。 ドキュメントで会話する これは大きく動きとして変わったところです。 今まで自分たちはドキュメントを会議のために作っていましたが、非同期からはドキュメント上で議論するために作っていた。 これは書き方や何を話したいかなども整理され、自分たちのコミュニケーションの幅を広げる良い活動になりました。 時間がある価値を認識する 定性的ではありますが、チーム全体として時間ができることによって考える時間や作業時間が増えたという感想があった 自分たちが得たのは朝会の時間だけだったが、それでも生産性があがり考える時間を増やすことへの価値はとても高いものだと感じた。 同期で得ていたものを理解する 自分達が同期のコミュニケーションで知らず知らずのうちに人柄を認識したり その日の体調や気分を会話のトーンから情報を得たりなどMTGの役割以上に情報を得ていたことに気づけたのは収穫でした。 議論や質問内容が自然とドキュメントにログとして残る 自分達が非同期化をすることで議論などの内容が残り、当時どのような議論をしていたかなどが検索可能になりました。 これにより会議をする ⇒ ドキュメントを書くではなくコミュニケーションをとったものがそのまま残せるようになりました。 非同期で失ったもの チームで同じ時間共有し過ごす総量 朝会はアイスブレイクしてから自然と話していましたが、同じ時間を共有して同じ情報をもらって雑談することはチームビルディングの一部になっていました。 これをなくすことによりチームが共有した同じ時間の総量が減ったことを認識していませんでした。 リアルタイムな返答 実際に緊急対応などは別途MTGの予定を入れるなどしなければ迅速に動けなくなるなど、朝会のおかげでできていたことを補完する動きが必要になりました。 失ったものへのアクション チームで同じ時間を共有し過ごす総量 朝会がチームビルディングにつながるコミュニケーションを一部補っていたことがわかったので 明示的にチームビルディングの時間をとることにしました。 あくまでドキュメントでやるのは作業に必要な報告・共有の業務で チームを良くするための活動は別途するという形にすることでチーム感が薄くなったという意見は薄くなりました。 リアルタイムな返答 緊急度が高い内容などはSlackでメンションするなど即時の返答が可能になるようなアプローチをしました。 また、すぐに返答が欲しい場合などはMTGを行い一気に収束させるなどで補完しました。 感想 自分達が非同期の動きを取り入れたことでチームとしての動き方の選択肢に幅が増えたと共に 自分達がMTGで何をしていたかを認識できました。 また、非同期での動きをすることで同期でやることの価値なども認識できたので どのようなときに同期的に動くかも明確にしていくことができそうだと感じています。 今後 現在は小さいチームでこの非同期の文化を作っているため明示しなくても伝わっている暗黙知のようなものがいくつかあると感じています。 今後はこれらをカルチャーやルールに落とし込み新しい人が非同期の動きにすぐ馴染めるようにしチームがスケール可能にしたいと考えています。
アバター
スマートキャンプでエンジニアをやっております永井です。 日毎に寒気加わる時節となりました、皆さまいかがお過ごしでしょうか。 今年も弊社プロダクトチームで開発合宿を開催しました。 そこで本記事では合宿の目的や様子をご紹介しようと思います。 今回の合宿も去年と同様に以下の感染症対策を充分に行い実施しました。 参加者全員の抗原検査、検温 一定時間ごとに換気 合宿の目的 テーマ 会場 やったこと 事前準備 合宿の様子 成果発表 合宿を終えて スキル面 コミュニケーション 合宿の目的 弊社は2018年より毎年開発合宿をしており、「チームで企画からプロトタイプ開発まで一気通貫でやりきる経験」や「初めて一緒に業務をするメンバーがいることによる気づき」などとても価値がある施策だと考えています。 そこで今年の合宿の目的としては以下の3つを掲げました。 テックカンパニーを牽引していくエンジニア組織 として、スマートキャンプの 未来につながるアイディア を創造する テックカンパニーを牽引していくエンジニア組織 として、スマートキャンプの 未来を支える技術力 を向上させる これから 組織として大きくなっても壊れない頑丈な絆 を形成する テーマ また、今回の合宿では 「スマートキャンプの新規事業としてテクノロジーで成長させられるプロダクトを創造する」 というテーマも掲げました。 これからテックカンパニーを目指すうえで、次の柱となるプロダクトを生み出すことは必要不可欠です。そしてただ生み出すだけではなく、労働集約型のサービスではない、開発主体でサービスをグロースさせていけるものである必要があると考えました。 よって開発するプロダクトは 「社会の非効率をなくす」「将来的にテクノロジーでサービス成長できる」 ことを重要視しました。 またアイディアも優先順位を以下のように指定しました。 テクノロジー 新規性 (マネタイズ) 全くマネタイズアイディアがないのはNG 会場 今年は千葉県香取市にある農園リゾート「THE FARM」にて行いました。日本初の牧場グランピング施設で、貸農園や野菜収穫体験農園がある宿泊施設です。 www.thefarm.jp HPには「都会の喧騒を離れ〜」とありましたが、都会にはあまり無い自然豊かで広々とした場所で、いるだけでもリラックスできる良いところでした。 また施設内には温泉やサウナ、カフェなどが一緒になった「おふろcafé かりんの湯」もあり、非常に過ごしやすい場所でした。セルフロウリュができるサウナもあるのでサウナ好きにはたまりませんね! www.thefarm.jp 天気は快晴で気温もちょうどよく、絶好の開発合宿日和となりました。 奥に見えるテントが宿泊したグランピング施設です。 やったこと 合宿は11/9〜11/11の2泊3日で行いました。 参加者は5人 × 4チームに分かれました。 「組織として大きくなっても壊れない頑丈な絆」を作るため、実務であまり一緒になったことが無く、また職能もバラバラな人達になるようにチーム編成をしました。 そして今回のテーマである「スマートキャンプの新規事業としてテクノロジーで成長させられるプロダクトを創造する」に沿った形で、各チームは新規サービスの企画からプロトタイプの開発まで行い、最終日にプレゼンを行いました。 事前準備 移動時間などもあるため3日間丸々使えるわけではなく、企画から始めるとそれだけで合宿が終わってしまいます。 なので1~2ヶ月前から各チームで案出しやプロトタイプはどこまで作るかなどを話し合い、空き時間で開発環境の構築も進めました。 準備の目安も運営で以下のように定義しました。もし開発合宿をお考えの方がいらっしゃいましたら参考になれば幸いです。 作りたいプロダクトのコアコンセプトが明確になっている 合宿中に作りたい機能群を具体化しておく 誰がどうやって使うものかをコアコンセプトから落としてくる 必要な技術についても考えておく 簡単なペーパープロトのようなものがあるとなおよし 技術的な懸念点がない、もしくは明瞭である 懸念点がないように調査しておく、または合宿中で懸念点を払拭する 合宿中で懸念点払拭する場合は、もしだめだった場合の代替案も考えておく エンジニアはリポジトリ作成やAWSの環境準備など、下準備をしておく どこまで事前にやるかは各班・各人に任せます 当日のタイムスケジュールを考えておく 進捗確認のタイミングや連携をとるタイミングなど メンバー全員が「どんなものを作るか」「だれが何をするか」「どこまでやるか」を共通認識取れた状態にしておく 中には上記の準備だけでは無くCI/CDを組んでいるチームもいて、力の入りようが伺えました。 合宿の様子 開発の進め方はチームによって多種多様で、話しながら実装するチームもいれば打ち合わせをして各自実装をしているチームもいました。 疲れたら雑談でもしながらご飯を食べます。外だと開放感があって良いですね。 近くでは焚き火をやっていたので火を見ながら開発もできました。ちょっとエモい。 夜はBBQをしたり…。 焚き火をやっていたのでマシュマロを焼いたり…。 気分がノッてくると夜もガリガリと開発を進めました。 2日目は開発の合間に皆で農業体験をしました! 天気が良くてよかったです(ちょっと暑かった……) (農業体験あとで切り替えが大変だったのはさておき)その後も実装を続けました。と同時に発表用のスライドづくりも行い、どう発表するかも話し合います。 成果発表 3日目の最後には各チームでプロダクトについて発表しました。 発表内容は以下の内容で行いました。 プレゼン Vision, Mission 優位な機能3選 リーンキャンバス グロースアイディア、展望 ソフトウェアプロトタイプ コンセプトがわかりやすいもの 技術的に重要な要素を再現したもの、優位性を再現したもの JSフレームワークのSvelteを使ってフロントエンド開発をしたり、機械学習など日常の業務ではあまり触れていない技術分野にもチャレンジしつつ開発した新しいサービスを発表し合いました。 実際に動くものを見せられるのは開発合宿ならではですね。 最後に皆で「技術的にチャレンジをしているかどうか」「スマートキャンプで実現できそうか」などの項目で投票し合い、結果を元に授賞式を行い合宿は終了しました! 具体的な内容まではお伝えできませんが、優勝したプロダクトを始めこの合宿で出たアイディアが未来のスマートキャンプを支える礎になれば良いなと思います。 合宿を終えて 目的でも述べた「チームで企画からプロトタイプ開発まで一気通貫でやりきる経験」ができた合宿だったと思います。 スキル面 企画もそうですが、ゼロからのアプリケーション開発やインフラの構築など普段ではあまり触れないことを経験する良い機会になりました。 また機械学習もそうですが、「普段はRubyでの開発なのでGolangで作ってみる…」など技術面での新たなチャレンジも通じて技術力の向上の良い機会にもなりました。 エンジニア以外のメンバーも開発したり、普段デザインを考えることが少ないメンバーもデザインを考えてみたりと職能の壁を超えた経験を積むことができました。 コミュニケーション 最近は人数も増え、テレワークも相まってあまり話さないメンバーとも直接コミュニケーションを取る良い機会となりました。また今回の目標にもある「これから 組織として大きくなっても壊れない頑丈な絆 を形成する」こともできたと思える合宿となりました。 この経験を日々の業務に活かして頑張っていきたいと思います。
アバター
設立して半年、京都開発拠点をエンジニアリングマネージャーが振り返る スマートキャンプでエンジニアリングマネージャー(EM)をしている瀧川です。 弊社の京都開発拠点は、2022年6月1日に設立したエンジニアが中心の新規拠点となります! 私は静岡生まれ東京育ちで特に関西に縁があったわけでもないですが、EMとして0からの拠点作りに惹かれたこと、リモートワークの普及で郊外に引っ越す話がよく聞かれ始めたこと、京都という響きに惹かれたことなどから、家族での移住し参画を決めました。 正式な設立日は2022年6月1日ですが、設立メンバーは2022年5月から京都に集まり活動を始めていたため、早いものでもう半年経つことになります。 半年間、たくさんのトライをして、うまくいったり、うまくいかなかったり、多くの経験を積むことができました。 拠点立ち上げってどんなことするの?京都でエンジニアを集めるメリットってあるの?タイトルを読んでそんなことを思われた方はぜひ一読いただければ幸いです! 設立して半年、京都開発拠点をエンジニアリングマネージャーが振り返る スマートキャンプ京都開発拠点とは 拠点の業務 京都開発拠点の半年 拠点全般 開発 エンジニア採用 インターン受け入れ 京都開発拠点のこれから 最後に 面談のご案内 スマートキャンプ京都開発拠点とは スマートキャンプ京都開発拠点は2022年6月1日に設立したエンジニア中心の拠点です。 京都開発拠点では中長期で弊社Visionである「テクノロジーで社会の非効率をなくす」ことを目指した組織開発・プロダクト開発を推進するべく拠点運営をしています。 これは全社としてテクノロジーへの投資を強化する取り組みの一つとして位置づけられています。 昨今リモートワークが一般的になり、ツールの発展も相まって、地理的にどれだけ離れた場所でも不便なく一緒に仕事ができるようになりました。 ではなぜこのタイミングで新たに開発拠点を立ち上げたのかですが、 私たちは好きなところで働きながらも、日々の業務を一緒の空間でコミュニケーションを取りながら進め、それを楽しむような働き方 を推していきたいという想いでも立ち上げています。 なので、新規開発拠点立ち上げというわからないことだらけの日々を、必要なときに顔を突き合わせディスカッションをし楽しみながら、全社に大きなインパクトを与えることを目指すのが京都開発拠点としてのバリューになります。 拠点設立当時の思いについてはこちらにも記載しているので、興味があれば併せてご覧ください! 京都で「社会の非効率を無くす」プロダクト作りを。スマートキャンプの開発拠点を設立します。|スマートキャンプ公式note『.▲.tent.』|note 拠点の業務 スマートキャンプとしてエンジニアの拠点を立ち上げるのは初めてであり、また上記目的だけが課されている状態だったので、本当に0から拠点メンバーでアイディアを練り行動を起こしていく必要がありました。 その中で最初に想定したミッションとしては主に以下となります。 共通基盤開発 プロダクト横断で価値を生む基盤作り エンジニア採用 新しいチャネルの開拓 京都ならではの訴求 インターン採用 学生へのチャレンジ機会創出 立ち上げメンバーは、拠点長としての対外的な業務やPOなどの役割を担う高橋、採用とエンジニアマネジメントを担う私瀧川、開発とインターンマネジメントを担うエンジニアの3名で、ざっくり役割分担しつつも互いに助け合いながら半年を過ごしました。 ※ 今回の記事はEMとしての瀧川視点ですが、拠点長の高橋から見た視点に興味があればMeetyなどでご連絡いただければと思います! meety.net 京都開発拠点の半年 ここからは京都開発拠点を開設してからの半年間を振り返ってやったこと、それに伴って考えたことをつらつらと書かせていただきます! 拠点全般 立ち上げメンバーの意思統一 早期に成果を出すには、自分たちが何にコミットメントするのか、どういった価値観を大切にするのかをメンバー同士ですり合わせ、明文化することが重要だと考えていました。 そこで全員でインセプションデッキをやったり、拠点のキャッチコピーを決めたり、取り決めをすべてドキュメントに残すなど意識して行動しました。 特にキャッチコピーの「Go Lightly」は、せっかくの新規拠点なので身軽に意思決定をしようと考え決めましたが、難しそうなチャレンジでも提案するとメンバーがやってみましょう!と言ってくれており、カルチャーの土台となっているなと感じています。 オフィス 「スマートキャンプ京都開発拠点とは」で書かせていただいたとおり、京都開発拠点はオフラインでのコミュニケーションも大切にしたいという思いもあり設立しています。 特に今の設立初期だと不透明なことが多く、都度自分たちでディスカッションをしながら方針など調整し業務を進めていく必要があります。 そのため私たちは現在週2日を目安に出社することをルールとしており、その2日にできるだけディスカッション系のMTGをまとめるようにしました。 ※ 全社的には週1日目安での出社が推奨されています。 出社するオフィスはグループ会社であるマネーフォワードが4年ほど前に先んじて京都に開発拠点を設立しており、そちらと同居させていただいています! 当初は5人定員の薄暗いレンタルオフィスを借りて始めようか…という風に考えていたんですが、拠点設立について相談していた中で同居の提案をいただき実際に何不自由なく拠点の一員として現在過ごせているのはとてもありがたいことだと感じています! kyoto.moneyforward.com 実はせっかくマネーフォワードの方々と同じ拠点にいるので、積極的にコミュニケーションを取り、よりシナジーを生み出そうというのを拠点の裏目標にしています。しかしながら今のところは軽いコミュニケーションや意見交換会しかできておらず、ここについてはまだまだできることがありそうだと感じています。 一緒にお互いの事業・プロダクトをフォワードできる取り組みが先々できるように考えていきたいです! 東京のメンバーとのコミュニケーション 京都開発拠点ができる前から弊社ではGatherというバーチャルオフィスを導入していました。 このGatherの運用がうまくいっていたこともあり、実際に京都に来る前と後で、各メンバーとのコミュニケーションが取りにくくなったと感じることはほとんどありませんでした。 ※ Gatherを弊社で導入した際のブログがこちらです。 ZoomやDiscordではなくGatherをリモートワークのコミュニケーションツールに選んだ理由 - SMARTCAMP Engineer Blog 良かったこととしては京都という土地柄か、東京のメンバーが仕事でもプライベートでもなにかと用事を作ってよく訪問してくれたことはとてもうれしく思っています。 物理的な距離は遠くなりましたが、逆に関係性としては近づいたところもあるなと感じています! 東京のメンバーと三条大橋近くにて 京都市との連携 当初はあまり想定していなかったですが、京都市と関わらせていただくこともありました。 京都市としてIT企業の誘致に力を入れていることもあり、拠点設立に際した補助金や意見交換会の実施、市主催のイベントへの参加などさせていただきました。 https://www.city.kyoto.lg.jp/sankan/page/0000296666.html www.city.kyoto.lg.jp 2022/6/14に拠点開設イベントを開催したのですが、そこでは京都市の産業イノベーション推進室の方、京都信用金庫の企業成長推進部の方、マネーフォワード京都開発拠点拠点長の村上さん、そして弊社拠点長の高橋による公演や、パネルディスカッションをしていただきました。 私も司会をさせていただきましたが、TVニュースで取り上げていただき地上波デビューしたりとなかなかない経験が詰めていると感じました! こういった取り組みを通して繋がりを増やし、お互いにメリットのある施策を企画していけるとよいなと考えています。 開発 京都開発拠点のミッションを中長期でMissionの「テクノロジーで社会の非効率をなくす」を胸を張って実現できていることとして置いたときに、どんな開発を担うべきかについてメンバーでディスカッションし、短期的にはプロダクト横断の共通基盤開発に注力することとしました。 現在弊社は複数プロダクトを抱えていますが、それぞれが事業単位でバーチャルカンパニー制をとっており、独立して開発・運営をしています。 そうすることによって、よりフォーカスした運営ができ、開発も円滑になりましたが、その代わりに地続きなプロダクト郡を展開しているにもかかわらず、プロダクトが相互に連携してユーザーに価値提供する機能が手薄といった課題感がありました。 またこれから新規プロダクトにチャレンジする際も、連携を検討する場合都度開発工数がかかってしまいスピード感が損なわれる懸念もあり、まずこの部分に私たちが手を入れることにしました。 具体的には認証を一元管理する基盤、各種データを分析・活用する基盤などを開発予定です。 技術面においては、弊社はバックエンドの実装がRuby on Railsになっているプロダクトが大半のため、そちらを修正および切り出し、マイクロサービス化する際にGo + gRPCを使っていく想定としています。 ただやることが決まったものの、ただでさえ影響範囲が広いシステムで意思決定の難易度が高い中、エンジニア2名かつ手を動かすのは1名という体制で進める必要があり、サポートのため技術顧問をしていただいているYoshiori-sanに定期的に相談しながら進めています。 技術顧問のヨシオリさんと歩んできた半年間について話しました - SMARTCAMP Engineer Blog エンジニア採用 エンジニア採用については、最近傾向が掴めてきたかなと感じています。 設立背景もあり、現在は募集要件として「京都近郊に住んでいるまたは引っ越し意思がある」ことを明記しています。 まず母集団だと、京都を希望勤務地に入れている方は非常に少ないです。大阪・兵庫・滋賀・奈良を加えても、関東希望に比べて遥かに少ないです。 そのうえで最近では関東希望の方にもお声がけさせていただくことも増やしています。 理由としては、京都は特別U・Iターンをしたいと考えている方が多いと感じているからです。 実際に多くの方と面談させていただく中で、「大学時代を京都で過ごしいつかは京都に帰りたかった」「旅行で京都に滞在して住んでもいいと思っていた」とみなさんおっしゃっており京都がいかに魅力的な土地かを肌で感じています。 また、他ポジションでの採用では、昨今エンジニアが売り手市場ということもあり、多くの企業と接点を持たれ検討されていることが多いため、他企業の選考状況と合わせるために選考フローを変えたり、競うように自社のことをよく見せたりと、本質的に企業と候補者の方のマッチ度をはかるのは難しいと感じていました。 それに対して、「新規拠点立ち上げ」「京都」というキーワードを掲げていることで、あまり転職意欲の高くなく積極的に転職活動をされていない方に興味を持っていただくことも多く、その分しっかりと一人ひとりの方と時間をかけて向き合い、ミスマッチの出にくい選考ができていると感じています! インターン受け入れ 私たちが京都を選んだ大きな理由の一つとして、京都が優秀な学生がたくさん集まる学園都市である、というのも挙げられます。 そのなかで、最近では情報系の学部を新設するところも増えており、エンジニアを志す学生が多くいるのに、東京と比べてしまうとインターンの受け入れ先が少ないという話をさまざまなところから聞いていました。 そこで私たちが新しい受け入れ先となり、スキルアップしてもらえる環境を整えることで、学生の方の成長や育てることによる社員の成長、そしてお互いにマッチしていれば新卒として受け入れができるとWin-Winだと考えています。 それらを目指して以下のことに取り組みました。 インターン採用 インターン時給調整 インターン用タスク収集フロー整備 インターン行動規範策定 結果として現在(2022/11)で2名のインターン生の受け入れをしています。 インターン採用 設立と同時に募集を開始しましたが、これまで多くの方に応募いただき、やはり長期インターンの需要の大きさを感じていますし、また面談させていただく中でスキルが高く熱量も高い方が本当に多いなと感じました! 募集する前はインターンもリモートワーク普及の波を受けて、優秀な方は遠方でも東京の企業のインターンに参加しているんじゃないかとも考えていたのですが、実際に話を聞いていくとサマーインターンなど短期のインターンはリモートでの募集もあるが長期インターンでは少ないことや、リモートだと社員とのコミュニケーションが満足に取れるかが不安という話を聞き、自分たちが京都でインターン採用をする意義を強く感じました。 現状は管理コストなど加味して枠をかなり絞らせていただいてますが、今後受け入れ体制の拡充など通して多くの方に参加いただけるようにしていきたいです。 www.wantedly.com インターン時給調整 優秀なインターンの方にジョインおよびスキルアップしていただくために私たちが重要だとなことの一つが、難易度の高いタスクを適切に任せ、それに対して適切な報酬を支払うことだと考えました。一方で、インターンは学生を学ばせてあげる場という考え方の企業が多く、エンジニアの時給としては低く設定されることも多く見受けられました。 私たちはしっかりと成果を求めることで成長を促したいと考え、ベースの時給アップやスキルや成果による時給アップ制度の作成に取り組みました。 まだインターンの方も稼働を始めたばかりで、実際どれくらい成果を出せるようになるかなど不透明ではあるので、こちらは実態に合わせて柔軟に変えていきたいと考えています。 インターン用タスク収集フロー整備 インターンを採用するうえで一番ネックになるのは従事するタスクの創出だろうと考えていました。 そこでいくつかの仕組みを考え、定常的にタスクを用意できるように心がけています。 各プロダクトのPdM、エンジニアリーダーに優先度が下がったタスクをインターンタスク置き場に移管してもらう 定期的に各プロダクトのバックログを回遊し期日のないタスクを移管する 自分たちで各プロダクトの課題などをディスカッションする機会を作ってタスクを作成する しかしこちらではまだまだ不十分ですし私たちが手を動かすコストも高いため、追加の施策を考え中です。 インターン行動規範策定 京都は現状社員が少人数のため、インターンを増やせば増やすほど管理工数がかかってしまうのは想定できました。 それに対応するため、インターンの行動規範を定義して、よりインターン生が自走しやすい環境の整備を目指しました。 この行動規範はインターン生からFBを受けながら追記・改善をしています。 インターン行動規範 京都開発拠点のこれから ここまでで振り返ったこと全般的に、学びは非常に多い一方で、明確な成果はまだ出せていないと考えていて、引き続き行動を取り続けていくのが第一だと思います。 特に短期的にはエンジニア・インターンの採用はまだまだ改善の余地があると考えています。 エンジニア採用においては、京都は東京と比べるとエンジニアの転職が身近ではなく、潜在層が多いイメージなので、そういった方々にアプローチするイベントの開催や京都の他企業と連携したイベントなどが今後の施策候補として挙げられます。そしてインターン採用についても大学に訪問させていただいたり、ハッカソンの開催などできればと考えています。 また当初想定になかったところだと、来年度より京都開発拠点で新規プロダクトの開発体制作りにもチャレンジしようと考えています。 SMARTCAMP NEXTという新規プロダクトのコンペが全社的に開催されたりと、新規プロダクトを通じてスマートキャンプのMissionである「テクノロジーで社会の非効率をなくす」を果たす動きが加速しているのもあり、京都開発拠点でもそうした動きの一部を担うことにしました。 そのため、アイディア創出に繋がる新規プロダクトコンペへの積極的な参加や、PdMの採用強化、今まで明文化されていなかった新規プロダクトの社内エスカレーション・リリースフロー整備などにも取り組みたいと考えています。 ※ 実際に10月から開催されているSMARTCAMP NEXTに京都から6アイディア出し、2アイディアが最終選考に残っています🎉 SMARTCAMP in Kyoto 最後に 長文になってしまいましたが、京都開発拠点を設立してから私たち立ち上げメンバーが経験したことを書かせていただきました! メンバー同士工夫しつつ多くのチャレンジができた一方で、反省点ややりきれていないところが散見している現状ですが、EMとしての業務以外にも多くを学ぶことができたとあらためて感じました。 まだ半年、次の半年にはまた多くのチャレンジをして振り返りたいなと思います。 ぜひ見ていただいた方の何か参考になっていれば幸いです! 面談のご案内 途中で拠点長のMeetyを載せましたが、私もMeetyをやっているのでぜひ聞きたいことがあれば気軽にお声がけください! (ブログには書けないような濃い内容もお話できると思います) meety.net
アバター
ご挨拶 はじめまして、2022年7月1日に入社した末吉です。 スマートキャンプでは、BALES CLOUDの開発に携わっております。 今回は入社エントリということで、簡単な経歴から、 スマートキャンプを選んだ理由や入社してみてどうだったかみたいなところを 書いていければと思っております。 また、私が本格的に開発を始められたのは25歳からであり、 スタートが遅かったのでそういった方の参考にもなれれば嬉しいです。 ご挨拶 経歴 テスター時代 やっと開発に辿り着いた もっといい設計をしたいもっといいコードを書きたい スマートキャンプへ転職 なせスマートキャンプを選んだか いいものを作れそう 人柄が良さそう 最適な労働環境 入社してみて ノビノビ快適 今までのやっていた開発がいかに非効率か痛感した テストコードってめちゃくちゃいい 前職との違い 入社後してたこと まとめ 経歴 まずは簡単に現在までの経歴を紹介したいと思います。 テスター時代 まず最初の会社では、客先常駐でテストをやっておりました。 もともと開発がやりたかったのですが、テスト仕様書に従いながらアプリを操作する日々で、 「このままではやばい。。。」と思いながらも転職活動に踏み切れずにいました。 そんな時に当時常駐していたチームの元リーダーから、 「人が足りていないから来ないか?」というお誘いがあり、転職をしました。 2社目ではQAとしてテスト工程の管理をすることになりました。 若干はスキルアップしたのですが、開発には携われず、 やはり開発がやりたいと思い転職を決意しました。 やっと開発に辿り着いた 3社目(前職)でようやく開発に辿り着き、主にSIerに常駐してWebアプリやiOSアプリの開発に携るようになりました。 もっといい設計をしたいもっといいコードを書きたい 常駐していたところでは、受託開発ということもあってか、 「納期が最優先」「既存部分はできるだけ触らない」というような方針でした。 そのため、「ここを少し触るだけでもっと良くなる」といった状況でも、 「妥協した既存を触らない方法」を取らざるを得ませんでした。 次第に、もっといいものを作りたいという思いが強くなっていきました。 スマートキャンプへ転職 「これらの不満を解消するのには自社開発へ行くのが最善」だと思っていたことと、 「年齢を考えると自社開発へ行くなら今しかない」という思いから転職を決意、 スマートキャンプに入社しました。 なせスマートキャンプを選んだか 当時、転職活動を始めたばかりで「そんなに早く決まらないだろう」と思っていたことや、 「インサイドセールス」という言葉を知らなかったこともあり、 最初は練習がてらのような軽い気持ちで面談を受けました。 いざ受けてみると下記などから、面接が進むごとに「入社したい!」と思うようになりました。 いいものを作れそう 経歴でも紹介しましたとおり、前職ではもっと品質にこだわった開発をやりたいと思っていました。 そんな中、面接で「納期のために品質を犠牲にしたりすることはない」という方針を聞き、 ここであれば品質を大切にした開発ができそうであると感じました。 またPdMの「エンジニアの意見を大切にしている」という考えや 「ドメインについての経験があり、知識が豊富」という点も非常に魅力的でした。 「エンジニアの意見を大切にしている」点からは、 「"仕様のせいでコードが複雑になり内部品質が悪化する"といったことがない」と、 「PdMがドメインに詳しい」点からは、 「ユーザーが本当に必要としているものを作れる」と感じたためです。 人柄が良さそう スマートキャンプの面接では、会ったすべての方の人柄が非常に良く魅力的でした。 面接の会話での雰囲気は当然のことながら、 労働環境の話から子供の話題に発展し会話したことからも、人柄の良さや働きやすさを感じました。 最適な労働環境 私は現在子供が2人いるのですが、夫婦共働きしております。 そのため「フレックス」かつ「リモート」という環境は、最適な労働環境でした。 「リモート」という環境については、嬉しい反面、 「馴染むのに少し時間がかかるかも」という懸念も少しありました。 ただ実際には、入社直後は1on1が多く設定されていたり、プロダクト横断でのMTGがあったりして、 チームにはすぐ馴染めました。また、特に不便に感じるようなこともありませんでした。 ちなみにこれは入社後に始まったものですが、 BALES CLOUDの開発チームではドキュメント文化を推進しており、 さまざまなものを非同期化しようとしております。 現在非同期化できているのは朝会のみですが、朝会だけでも細切れの作業が減り効率が上がっております。 また、次第に相談などの付随したものもドキュメント化および非同期化されていき、 これによってMTG時間の短縮や、Slackによるコミュニケーションコストの増加が低減したりといった効果もありました。 課題は色々ありますが、非同期化がうまく進むと、 作業効率が向上したり働き方もさらに融通が効くようになると思われるため、 ドキュメント文化がさらに進んでいけば嬉しいなと思っております。 入社してみて ノビノビ快適 どんなに良く見える会社でも、本当に良いのか?自分に合うのか?は 入ってみないと分からないと思っています。 なので、少し期待が外れる程度は仕方ないと思って転職したのですが、 驚くほど期待外れの部分がありませんでした。 すごくノビノビできていて現在すごく快適です。 今までのやっていた開発がいかに非効率か痛感した 今まで携わっていた開発では、テストをExcelで書いていたり、 テストコードを書いていてもが老朽化していたりしました。 入社して3ヶ月経過しましたが、これらが如何に非効率でかつ品質を下げるものであるかを実感しました。 テストコードってめちゃくちゃいい 入社してから自分の中で一番良いと思っている変化がこれです。 前職で携わっていた開発でもテストコードを書くことはありました。 ただ納期を優先するあまり、「テストコードを書く時間がないから手動でテストする」といったことが多くありました。 一度これをやってしまうと、終わりの始まりです。 次の開発ではテストコードのメンテナンスから始めなければなりませんが、 前回の開発で時間がなかったのにも関わらず、今回の開発でメンテナンス分の時間が余るわけがありません。 その結果、テストコードを書かなくなり、テストコードが老朽化していき、使い物にならなくなってしまいます。 こういった経験から、入社前までは、テストコードがいいものだとは認識しつつも、 「メンテナンスが大変」という意識も少なからずありました。 BALES CLOUDでは、工数を見積もるときはテストコードも含めた工数を出します。 また、時間がないからといってテストコードを省くこともありません。 これによりテストコードの鮮度を保つことができており、以下のようなテストコードの恩恵を受けることができております。 恩恵の1つ目は、不具合の発生率を低下させられていることです。 私がコーディングしているときに、「修正してテストコードを実行したら、想定外の箇所でエラーが出て助かった」ということがありました。 テストコードがなければ、リリース後に不具合として上がってきたであろうものもあったかと思います。 リリース後の不具合となれば、不具合報告をヒアリングする工数であったり、調査する工数であったりと、 実装時に気付けていたら発生しなかった工数が余分に発生します。 もしこういったことが続いてしまうと、次第に機能開発に割く時間が減り、開発スピードも下がります。 恩恵の2つ目は、リファクタリングを積極的に行なうことができていることです。 私がチームにJoinしてから今までの短い期間でも、 軽微なものや少し大きめなものまで、リファクタリングは何度も行われております。 もしリファクタリングがされていなかったら、構造が複雑化して影響箇所が読みづらかったり、 単純に実装しづらかったりして、開発スピードも品質ももっと低下していると思います。 こういった体感ができたおかげで、私のテストコードに対してのネガティブな意識はすべて吹き飛びました。 結局はメンテナンスが大変というのは、目先の納期だけを優先するから大変になるのであって、 継続していれば負担になるものではないと今では考えます。 また、「テストコードがあるからこそ内部品質が維持でき、開発スピードを維持できる」という考えのもと、 テストコードはプロダクトを成長させていくための歯車であり、プロダクトを開発するうえで必須とも考えております。 前職との違い 色々と違いますが、やはり一番の違いは品質の考え方です。 繰り返しになってしまいますが、前職では納期優先で品質がおざなりになる場面が多々ありました。 スマートキャンプでは、「開発スピードと品質はトレードオフではなく、品質を上げることで開発スピードが上がる」 という考え方が浸透しているので、品質がおざなりになることがありません。 入社後してたこと 入社してからは、「システム構成理解」「環境構築」から始まり、 「軽微な機能追加」を経て、本格的なタスクに入るようになりました。 一番関わっているのはメール配信機能周りで、ライブラリとよく格闘しています。 まとめ ここまで読んでくださり、本当にありがとうございました! 色々と書いてしまって読みづらかったかもしれませんが、 レガシーな会社で開発をしていた経験があったからこそ、 スマートキャンプに入って色々と気づくことができたり、 本当のありがたみを感じられたと思っております。 同じような境遇に悩まされている方など、誰かしらの参考に少しでもなれたら嬉しく思います!
アバター
あいさつ こんにちは。スマートキャンプのデータアナリストのkumanomiです。 現在は BOXIL SaaS のデータ分析業務や社内のデータ民主化のため、小さいながらも日々改善を繰り返しています。 前職ではアプリエンジニアを経験した後にデータ周りを担当していました。 その際の職種はエンジニアでしたが、スマートキャンプではデータアナリストでの採用となりました。 スマートキャンプ内のデータアナリスト1人目です。 そのため業務内容は他社の同職の人がされている範囲とは違うかもしれません。 そんな僕がデータの役割について思うことを共有します。 データドリブン データ主導でビジネスの意思決定を行なうことをデータドリブンと言っていたりします。 例えば、うまい棒サラミ味が1本100円で売ってたら「高い」と思いますか?と質問されれば「高い」と答える人は大勢いるんじゃないかと思います。 なぜならうまい棒は1本10円や12円というデータとして、体に刻み込まれているからです。 データドリブンな意思決定を、私たちは日常から無意識のうちにしています。 日常の中ではできているのにも関わらず、ビジネスとなるとできなくなってしまうことがあるのではないでしょうか? 決定権をもった誰かの鶴の一声で施策や方針が決まってしまった経験はないでしょうか? 僕はあります。 言い方が良くないかもしれませんが、巻き込まれた側の認識だと間違いなくデータドリブンとは言えないんじゃないかなぁと思います。 そんな鶴の一声ですが、鶴の中に貯められたデータを用いて発せられたものである場合が多い印象です。人はこれを「勘」や「経験則」と呼んでいます。 データがDBにあるか鶴にあるかの違いなんです。 鶴の一声も一種のデータドリブンなのではないでしょうか? 意思決定に至るまでのデータが目に見えていないだけなのかもしれません。 データは共通言語 お偉い鶴も何かしらの意思決定をする際に、脳内でKGI *1 なりKPI *2 は考えているはずです。 何にも考えていなければ真の商売の天才か愚かな人です。 さまざまな異なる職種間で共通の認識を図ることができる1つの言語。それがデータなんじゃないでしょうか? データから抱く印象は担当部署、職種間で若干の違いはあるかもしれませんが、データによって ほぼ同じにように認識できる はずです。 データは共通言語 共通認識を阻害する要因 こんな感じのデータがあったとしましょう。 データがあることで「 ほぼ同じにように認識できる 」と上のほうで書きました。 ほぼというのは同じデータを見ても認識のずれが起きてしまう場合があるからです。 主に認識の誤差を生み出してしまう要因をいくつか抜粋しました。 各データ利用者の知識の差 新人、ベテランによってデータに対するイメージが違う場合があります。 最近の味を答えてくださいという問いがあったときに、新人はのり塩味、ベテラン勢はカレー味と答えたりするかもしれません。 説明情報が不足している 表のcodeのカラムはJANコードを示しているのですが、見る人によっては何を示しているのかわからない場合があります。 データが何を示しているものなのかを明記し定義することが大事です。 表記の揺れ 人によってはチキンカレー味のことをカレー味と言う人もいるでしょう。 略語であったり職場内の言語に置き換えられたりする場合に認識がずれてしまうことがあります。注意が必要です。 鮮度 データは常に新鮮なものを使っていきたいです。 あなたはうまい棒の値段を聞かれたときに何と答えますか? うまい棒といえば 10円 という記憶で止まってしまっている人もいるかもしれません。 2022年4月1日に値上げしてから、うまい棒は 12円 なんです。 別の例を挙げるならば、体調が悪そうな人に「大丈夫ですか?熱ありませんか?」と訊ねたところ、「あっ、大丈夫です!先週は平熱でした!」と答えられたらどうでしょうか? 過去のデータは過去のものです。データの鮮度に気をつけましょう。 実践 鶴は無能じゃないと僕は思っています。少なくとも僕が出会ってきた鶴の中で無能な人は1人もいませんでした。 ・・・本当は1人くらいはいたかもしれませんが記憶に残っていません。 日々インプットしているものが多すぎてうまく言語化できていないだけなんじゃないかと思います。 鶴からの依頼を受けたエンジニア側も、たとえ違和感があったとしても言語化することが意外とできていなかったりします。 なんでそんなことするんだろうと思うことがあっても、言い返す言葉に詰まることが僕にはありました。 そんなときにもデータを使って会話をして欲しいなと思います。 データがないときの鶴との会話 データがない時の会話です。 鶴に対して高すぎるという返しをしても、どう高いのか説明ができていません。 両者で物に対する価値観の違いがある状態です。データが加わるとどうでしょうか? データがあるときの鶴との会話 両者の間で金額データを元にうまい棒は12円なんだという 共通認識 を持つことができました。 数字で見えている以上、流石の鶴もここから押し通すことはないと思います。 もしもこれでダメなら話しても通じない人です。諦めてその場から全速力で逃げてください。 でも数字を元に仮説を立ててきた鶴の一声だったら、実装が多少面倒くさくても全力でサポートして欲しいなと思います。 たいへん希少な鶴だからです。 まとめ データは異なる役職、職種、部署間での共通言語としての役割もあると思います。 便利に正しく使って欲しいです。 僕はデータアナリストとしてスマートキャンプに入社しました。 僕の役割はBIツールを使うことでもクエリを書くことでもありません。 データを共通言語として定義していくこと、最新に保つこと、事業に活かせる状態にすることなんじゃないかなと実感しています。 *1 : 組織や企業が達成すべき最終的な大きな目標 *2 : KGIを最適に分解したもの
アバター
挨拶 おすすめする人 dotfiles とは dotfiles を使ってみた感想 セットアップ方法 リポジトリ構成 自動セットアップ アプリケーションの管理 カスタマイズ デスクトップアプリケーション CLI アプリケーション Mac App Store のアプリケーション 完成系 プログラミング言語の管理 カスタム例 設定ファイルのシンボリックリンク作成 カスタム例 .gitignore および README.md .gitignore README.md さいごに 挨拶 こんにちは!スマートキャンプエンジニアの石井(トマス)です。現在、 Boxil Event Cloud の開発に携わっています。 好きなことは「開発体験の向上」に取り組むことで、プロダクト参画時、開発環境をホストマシンに直接構築している状態で手順書もなく非効率だったのでDocker化し環境構築を簡略化しました。 今回は「開発体験の向上」と関連した、PC移行時に役立つ dotfiles について紹介します。 直近で、Intel MacからM1 Macへ乗り換える機会がありdotfilesを使って素早く環境構築ができたので、セットアップ方法やカスタマイズの仕方について話したいと思います。 おすすめする人 PCの乗り換えでこれからM1 Macを使おうとしている M1 Macの環境構築を楽にしたい 直近でPCの乗り換えはないが、乗り換えの際にアプリケーションや設定を忘れがち Time Machineを使った全ファイルの移行は不要。開発環境だけサクッと行いたい場合 皆さんは新しいPCを調達した際に環境構築をするのが面倒だと思ったことはないでしょうか? プログラミング言語のインストール、アプリケーションのインストール、設定ファイルの移行、、、移行作業って大変ですよね。 移行作業を簡単にするために、dotfilesを使った環境構築について話していきます。 dotfiles とは 「 .zshrc 」などの(.)からはじまる設定ファイルをGitで管理して、どこにいても自分の環境をサクッと作成しよう!というコンセプトです。 dotfilesについて詳しくない人は ようこそ dotfiles の世界へ がオススメなのでご覧ください。 本記事では、より簡単に環境構築するために「アプリケーション」「プログラミング言語」を含めて管理する方法について紹介していきます。 dotfiles を使ってみた感想 コマンド1つで環境構築できるようになり、環境構築の時間を短縮できました。 以前は移行元のMacから必要なアプリケーションを検索して、「ブラウザ」「Mac App Store」「Homebrew」など複数の経路からインストールしていました。 すべて手作業だったのでインストールが漏れることもありましたが、コード管理によりそういった心配もなくなりました。 セットアップ方法 実際にセットアップするときの流れになります。 GitやGitHubの操作については省略しているのでご了承ください。 GitHubに「 dotfiles 」リポジトリを作成。 後述の「リポジトリ構成」を参考に「 dotfiles 」リポジトリを更新。 セットアップコマンドを実行。 インストールするアプリケーションによって入力を求められることがあるので対応。 #セットアップコマンド bash -c "$( curl -fsSL https://raw.github.com/${github-username}/dotfiles/master/setup.sh )" ※セットアップコマンドは「dotfiles」リポジトリを使用する前提です。変更する際は /dotfiles の部分を修正してください。 リポジトリ構成 ここからは、リポジトリで管理するファイルについての説明です。 はじめに、(.)からはじまる設定ファイルを「 dotfiles 」リポジトリに移行します。 つぎに、「setup.sh」「.Brewfile」「_asdf.sh」「_link.sh」「.gitignore」「README.md」を「 dotfiles 」リポジトリに作成します。 私の環境だと、このような構成になりました。 # dotfilesリポジトリ . ├── setup.sh #セットアップ実行ファイル ├── .Brewfile #アプリケーション管理ファイル ├── _asdf.sh #プログラミング言語のインストール実行ファイル ├── _link.sh #設定ファイルのシンボリックリンク作成 ├── .gitconfig #設定ファイル ├── .zprofile #設定ファイル ├── .zshrc #設定ファイル ├── .gitignore #dotfilesのgitignore └── README.md #dotfilesの説明 vimを使っている人であれば .vimrc も管理対象になると思うので、下記のような構成になります。 # dotfilesリポジトリ . ├── setup.sh #セットアップ実行ファイル ├── .Brewfile #アプリケーション管理ファイル ├── _asdf.sh #プログラミング言語のインストール実行ファイル ├── _link.sh #設定ファイルのシンボリックリンク作成 ├── .gitconfig #設定ファイル ├── .zprofile #設定ファイル ├── .zshrc #設定ファイル ├── .vimrc #設定ファイル ├── .gitignore #dotfilesのgitignore └── README.md #dotfilesの説明 必要な設定ファイルは人それぞれだと思うので、自分の環境に合わせて追加/削除してください。 それでは、作成した「setup.sh」「.Brewfile」「_asdf.sh」「_link.sh」「.gitignore」「README.md」について説明していきます。 自動セットアップ 「 setup.sh 」はセットアップの実行ファイルです。 Xcodeのインストール、 rosetta のインストール、Homebrewのインストール、管理しているアプリケーションのインストール、プログラミング言語のインストール、設定ファイルのシンボリックリンクの作成の順に処理が流れていきます。 #!/bin/bash echo "Xcodeをインストールします..." xcode-select --install # rosettaのインストール。不要であれば下記1行削除してください sudo softwareupdate --install-rosetta --agree-to-licensesudo softwareupdate --install-rosetta --agree-to-license #------------------------------------------ # homebrew(arm64) #------------------------------------------ echo "homebrewをインストールします..." which /opt/homebrew/bin/brew >/dev/null 2>&1 || /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" echo "brew doctorを実行します..." which /opt/homebrew/bin/brew >/dev/null 2>&1 && brew doctor echo "brew updateを実行します..." which /opt/homebrew/bin/brew >/dev/null 2>&1 && brew update --verbose echo "brew upgradeを実行します..." which /opt/homebrew/bin/brew >/dev/null 2>&1 && brew upgrade --verbose echo ".Brewfileで管理しているアプリケーションをインストールします..." which /opt/homebrew/bin/brew >/dev/null 2>&1 && brew bundle --file ./.Brewfile --verbose echo "brew cleanupを実行します..." which brew >/dev/null 2>&1 && brew cleanup --verbose ### プログラミング言語のインストール echo "プログラミング言語をインストールします..." ./_asdf.sh ### シンボリックリンクの作成 echo "シンボリックリンクを作成します..." ./_link.sh exec $SHELL -l アプリケーションの管理 「 .Brewfile 」はHomebrewやMac App Storeのアプリを管理します。 「 brew install ~ 」や「 brew install cask ~ 」を打ち込んでいたアプリケーションをここで管理するイメージです。 「 .Brewfile 」のベース。 cask_args コマンドなど、Brewfileについては こちらの記事 が参考になります。 cask "..." などの部分は後のパートで解説します。 # インストール先の指定 cask_args appdir: "/Applications" # 外部ライブラリをインストール tap "homebrew/core" tap "homebrew/cask" # デスクトップアプリケーションの管理 cask "..." # CLIアプリケーションの管理 brew "..." # Mac App Storeのアプリケーションを管理 mas "...", id: xxxxxxxx 私が使っている .Brewfile を例にカスタマイズしていきます。 カスタマイズ デスクトップアプリケーション cask (package name) で設定。 brew install cask (package name) でインストールするアプリを記述。 # デスクトップアプリケーションの管理 cask "visual-studio-code" cask "google-chrome" cask "docker" cask "postman" cask "alfred" #ランチャーアプリ cask "drawio" #ダイアグラム作成アプリ cask "warp" #ターミナルアプリ。iTermから乗り換えました CLI アプリケーション brew (package name) で設定。 brew install (package name) でインストールするアプリを記述。 brew "asdf" brew "mas" brew "yarn" brew "tree" brew "git" brew "git-lfs" brew "docker" brew "awscli" brew "jq" brew "ag" brew "jump" brew "fzf" brew "bat" brew "gpg" brew "hstr" asdf と mas ライブラリは、「プログラミング言語」「Mac App Storeのアプリケーション」のインストールで必要なため最低限入れておいてください。 Mac App Store のアプリケーション mas (package ID) で設定。 Mac App Storeのアプリケーションをインストールするために mas-cli を使用します。 mas "RunCat", id: 1429033973 #システム状態監視ツール mas "Display Menu", id: 549083868 #ディスプレイ解像度変更ツール mas "Magnet マグネット", id: 441258766 #画面分割ツール idは「 mas search 」コマンドで検索します。 # Display Menuを検索する場合 mas search "Display Menu" 549083868 Display Menu (2.2.4) 完成系 # インストール先の指定 cask_args appdir: "/Applications" # 外部ライブラリをインストール tap "homebrew/core" tap "homebrew/cask" # デスクトップアプリケーションの管理 cask "visual-studio-code" cask "google-chrome" cask "docker" cask "postman" cask "alfred" cask "drawio" cask "warp" # CLIアプリケーションの管理 brew "asdf" brew "yarn" brew "tree" brew "git" brew "git-lfs" brew "docker" brew "awscli" brew "jq" brew "ag" brew "jump" brew "mas" brew "fzf" brew "bat" brew "gpg" brew "hstr" # Mac App Storeのアプリケーションを管理 mas "RunCat", id: 1429033973 mas "Display Menu", id: 549083868 mas "Magnet マグネット", id: 441258766 プログラミング言語の管理 「 _asdf.sh 」はプログラミング言語のインストール実行ファイルです。 バージョン管理ツールに asdf を使ってますが、他で気に入っているツールがあればそちらで代替いただいて大丈夫です。 以前使っていた anyenv より軽いので asdf に乗り換えました。 #!/bin/sh #install programming language which asdf >/dev/null 2>&1 && asdf plugin add ruby && asdf install ruby latest && asdf global ruby latest which asdf >/dev/null 2>&1 && asdf plugin add nodejs && asdf install nodejs latest && asdf global nodejs latest カスタム例 「 python 」を新しく追加したい場合はこのように書きます。 which asdf >/dev/null 2>&1 && asdf plugin add python && asdf install python latest && asdf global python latest ここにない言語のインストールやコマンドの詳細については asdf の公式サイト をご覧ください。 設定ファイルのシンボリックリンク作成 「 _link.sh 」は設定ファイルのシンボリックリンク作成の実行ファイルです。 (.)からはじまる設定ファイルを「 dotfiles 」リポジトリに移行したので、シンボリックリンク作成がないと設定を読み取ってもらえません。 #!/bin/sh # シンボリックリンクの作成 DOT_FILES=".gitconfig .zshrc .zprofile" for file in $DOT_FILES do ln -sf `pwd`/$file ~ done カスタム例 .vimrc を追加したい場合、 DOT_FILES="~" を修正します。 DOT_FILES=".gitconfig .zshrc .zprofile .vimrc" DOT_FILES="~" に追加されたものは、ホームディレクトリ直下にシンボリックリンクが作成されます。 ホームディレクトリ直下以外に作成したい場合は直接 ln -sf で指定するなど「 _link.sh 」を書き直してください。 .gitignore および README.md 「 dotfiles 」リポジトリを管理するためのファイルです。 書き方に決まりはないので、私の設定を紹介したいと思います。 .gitignore 管理対象を設定します。 ignore all ですべて管理対象外にしてから、 not ignore で必要なファイルを指定しています。 ### ignore all ### /* /.** ### not ignore ### !/.Brewfile !/.gitconfig !/setup.sh !/.zshrc !/.zprofile !/_link.sh !/_asdf.sh !/_anyenv.sh !/README.md !/LICENCE !.gitignore README.md 自動セットアップのコマンドと「Homebrew」や「Mac App Store」でインストールできないアプリを記載しています。 # Dotfiles ## スクリプトの実行 ターミナル起動 & スクリプト実行 bash -c "$( curl -fsSL https://raw.github.com/${github-username}/dotfiles/master/setup.sh )" ## その他 ### 手動インストール - Google日本語入力 - Karabiner-Elements - Karabiner-ElementViewer - BetterTouchTool - DisplayLink Manager さいごに 紹介したアプリケーションやプログラミング言語はほんの一例です。 自身に必要なものを追加したり削除したりしてカスタマイズを楽しんでください。 本記事が快適な環境構築に少しでもお役に立てれば幸いです。
アバター
スマートキャンプ、エンジニアリングマネージャーの入山です。 私は現在、弊社 BOXIL SaaS の開発部長を務めており、タスクの管理や開発メンバーのマネジメントを中心に行っています。また、 BOXIL EVENT CLOUD 開発メンバーのマネジメントも兼務しており、弊社エンジニア組織の中でも直接業務で関わるメンバーの数が多い立ち位置となっています。 そんな私は、2つのプロダクトの開発メンバーだけでなく、上長やPM、他チーム開発メンバーなど、頻度はさまざまですが10名以上の方々と日々1on1をさせていただいています。 1on1は入社当時から今に至るまで役職や立場が変化しつつ色々なメンバーと実施していますが、最近では自分との1on1に対する満足度が高いという声をいただく機会が増えたように感じています。 今回は、私が1on1を実施する際に意識している内容について、紹介したいと思います! スマートキャンプの1on1事情 全社 エンジニア組織 自分 1on1の目的 1on1で意識していること 自然体で臨み、最大限フランクな雰囲気を作る 傾聴だけでなく、自己開示を積極的にする 相手に合わせつつ、不変な自分でいる メンバーからの反響 まとめ スマートキャンプの1on1事情 スマートキャンプでは、すべての職種で全社的に1on1を実施しています。 なお、自分の入社は2018年10月ですが、その時から1on1は実施されていました。 最近では、社内で1on1に関するルールやノウハウに関するドキュメントが共有されていたり、外部講師を招いた1on1研修が行われたりしており、全社的により有意義に1on1を行なうための取り組みも実施されています。 また、1on1は基本的に上長とメンバーで行なうものですが、エンジニア組織ではメンバー間でも積極的に1on1を実施しています。 弊社の1on1事情を纏めると、以下のようになっています。 全社 上長とメンバー 最低30分/隔週以上(入社後3ヶ月間は週1以上) エンジニア組織 上長とメンバー(チーム内) 最低30分/隔週以上 メンバーとメンバー(チーム内) 最低30分/月1以上 メンバーとメンバー(チーム外) 最低15分/月1以上 ※過去実績を含む。組織人数や体制の変化に合わせて柔軟に実施。 自分 上長 最低30分/隔週以上 1名 直属メンバー 最低30分/隔週以上 5名 その他メンバー(PdM、他チームなど) 最低30分/月1以上 10名程 あらためて自分が1on1を実施している人数を見ると、かなり多人数になっていました…! 直近でエンジニア組織人数が増えていることや、自分の関わる範囲が広がっていることを感じました。 ※定期的に頻度やメンバーの見直しは実施しています。 1on1の目的 前述の通り、私は数多くの方々と1on1をさせていただいており、あらためて考えると業務時間全体の1割近く1on1を実施しています。 自分の業務時間の1割となると結構な時間に思えますが、各メンバーで考えると一人一人に向き合う時間は少ないため、この限られた1on1の時間を如何に有意義にできるかは特に意識しています。 相手との関係性や関係の深さによっても変化しますが、具体的に以下のような目的を持って1on1を実施しています。 【主な目的】 雑談を含むコミュニケーションによる信頼関係構築 気軽に何でも話せる(話して貰える)関係を作りたい メンバーの悩みや疑問点の解消 業務遂行や成長の妨げとなる要因を減らしたい ポジティブへの転換 1on1開始時より終了時で気持ちがより前向きになって欲しい この中でも信頼関係構築は特に重要だと考えており、これは弊社の技術顧問である 庄司嘉織さん が自分を含む各メンバーと初めて1on1をする際に伝えてくれた以下の内容にも影響されているものです。(2年程前ジョイン頂いた際に、以下のような内容を事前にドキュメント共有&口頭で説明してくれました) 愚痴や要望など、なんでも貯めずに、いつでも思ったときに伝えてほしい 1on1はそうやって思ったときにすぐに聞けるような関係性を作るためにやる 例えば上司だったときに「退職したいです」っていきなり伝えられたら負け できれば転職になる前に相談して欲しいし、相談して貰える間柄になりたい そういう意味でも1on1は「何かを報告するための場」ではなく、雑談をできるようにしておくことが大事だと思っている 上記嘉織さんの話を転記させて貰いつつ、1on1の最重要目的としてこれに勝るものはなかなかないとあらためて感じました。嘉織さんとは今も月1で1on1をさせていただき、いつもお世話になっています。ありがとうございます! 1on1で意識していること 今回の執筆にあたり、あらためて自分の1on1のやり方やスタンスを振り返り、その中から1on1を有意義にするために自分が意識していることをピックアップしてご紹介します。 自然体で臨み、最大限フランクな雰囲気を作る 1つ目に意識しているのは、自然体で臨み、最大限フランクな雰囲気を作ることです。 これは、まず自分自身が自然体で臨むことで相手も自然体になりやすい状況を作ることと、最大限フランクな雰囲気を作ることで何でも話せる相手や時間であることを感じて貰うことが目的です。 一般的に1on1という場は、部下のための時間であり、評価面談などと異なるフランクな雰囲気で行なうことが良いとされています。しかしながら、やはり上司と部下の関係である事実は変わらないため、お互いに身構えてしまって本音で話ができず、「話したいことが話せなかった。」や「辛い時間だった…。」と感じる1on1になってしまう可能性もあります。 また、個人的に過去辛かった1on1経験として、相手の体調やメンタルの不調に左右され、いつもなら言えることが言い辛かったり、必要以上に気を使って会話をしなくてはならないこともありました。(もちろん相手も人間なので致し方ない部分はあります。) こういった状況にならないように、自然体で臨み、最大限フランクな雰囲気を作るようにしています。 【意識ポイント】 自然体かつ常に安定した状態で臨めるように自分自身の体調やメンタルを管理する 体調やメンタルが整ってない日の1on1は避ける フランクな雰囲気や信頼関係を作るため、雑談や業務の明るい話題を多く話す 1on1時間の7割程雑談して本題に入ることや、雑談だけで1on1が終了することも…笑 傾聴だけでなく、自己開示を積極的にする 2つ目に意識しているのは、傾聴だけでなく、私自身の自己開示を積極的にすることです。 これは、私の自己開示をきっかけとして、相手がより自己開示をしやすい状況を作ることが目的です。 1on1で上司に必要なスキルとして真っ先に挙がるのが、傾聴だと思います。傾聴は、受容や共感といった聞き手のスタンスに加えて、相手の話を聞くことに徹するイメージが強いです。 しかし、上司が一方的に相手の話を聞くことに徹しすぎると事情聴取の様な雰囲気になってしまって本音が言い辛かったり、そもそも会話が盛り上がらなかったりする可能性もあります。 また、上司が自己開示をしていない場合、部下がふとしたタイミングで「1on1で自分の色々な話を聞いてもらってるが、自分は上司の事や考えはあまり知らないな…。」などに気付き、急に不信感や不安感に繋がる可能性もあると自分は考えています。これは自分の学生時代の原体験として、共通の趣味を持ち毎晩の様に会って話をしていた仲の良い友人に対して、ふとした時に「自己開示している自分とあまり自己開示をしない相手のギャップ」に気付いて急に心の距離感を感じてしまった経験があるためです。その時の不信感というか物悲しさは一瞬で関係を薄めてしまったため、自己開示の大事さを意識するようになりました。 ちなみに、心理学的にも「自己開示の返報性」というものがあり、相手が自己開示をした際に自分も相応の自己開示をしなければならない気持ちになる心理が働くとのことです。 上司側である私が先に積極的に自己開示をすることで相手に安心感を与えたり、メンバーが自己開示しやすい状況となるようにしています。 【意識ポイント】 信頼関係を構築のための自己開示 業務の事だけでなく、個人的なことも含めて率先して自己開示する 相手の自己開示も促すための自己開示 相手に何かを聞く際にまず自分の事や意見を添える よりよい傾聴をするための自己開示を惜しまない 相手に合わせつつ、不変な自分でいる 3つ目に意識しているのは、 相手に合わせつつ、不変な自分でいることです。 これは、自分の芯は残して一貫性を持たせつつ、相手の性格や話し方の癖、その日の状態に合わせて自分の対応方法を柔軟に変え、相手からの会話や本音を引き出しやすい状況を作ることが目的です。 1on1のやり方として自分流の良いスタンスが確立できたとしても、相手によって性格や人間性が異なるため、同じやり方では相手から最大限の会話を引き出すことはできないと考えています。そのため、相手や状況に合わせてこちらが柔軟に対応することが重要で、一言で1on1と言っても以下のようなスタンスを臨機応変に使い分けています。(基本的には1on1開始時の相手の様子を感じ取り、ほぼ無意識で決めている感じです) 【1on1スタンスの例】 最近どう?から入り、相手にトピックを出してもらう(基本はこれ) 長めの雑談から入り、相手がトピックを出してくれるのをひたすら待つ 相手が直近で悩んでそうなことに関する話題を自分から放り込む コーチング的に相手の思考整理のサポートに徹する ひたすら明るく楽しい系の話題を投げ続ける ひたすら相手に寄り添う このように色んなスタンスで1on1を実施していますが、気をつけなければならないのは、相手に合わせて対応方法を変えるだけで自分の意見や立ち位置を変えてはいけないということです。 極端な例ですが、AさんとBさんがモメている状況で双方と1on1をする場合、上司という立場上どちらにも寄り添いつつ2人の間の揉め事を解消するためのアプローチが必要となります。この時の相手への寄り添い方として、Aさんと話すときはAさんの味方、Bさんと話すときはBさんの味方、みたいなブレや矛盾が起きないように、自分としての一貫性を保つように気をつけています。 また、自分自身の無理のない範囲で相手に合わせることが大事で、間違っても相手に合わせて猫を被るようなことにならないように気をつけています。 当たり前だと思いますが、猫を被って表面上良いことばかりを言っていたり、メンバー間で話してて明らかに意見の矛盾が発覚したりするような人とは信頼関係を築くことはできないため、そういった事にならないようにも不変な自分であることを大事にしています。 【意識ポイント】 相手に合わせて柔軟に対応する 相手の性格や話し方、その日の状態に最適な対応を心がける 一貫性のある不変な自分でいる 柔軟に対応するが自分の意見や立ち位置は変えない メンバーからの反響 今回のブログ執筆にあたって、普段私と1on1を実施しているメンバーに、率直な感想やメンバー視点での分析を募集してみました。回答頂いた内容をご紹介します! Slackのスレッドをそのままキャプチャしているので、弊社組織の雰囲気も一緒に感じて頂けると嬉しいです。 (ちなみに私は社内で基本的に「あんにん」という愛称で呼ばれています笑) 初めて1on1に対する具体的なFBをいただき、私との1on1をポジティブに感じて貰えていたり、前述の自分が意識していることと相手が実際に感じていることに大きな乖離がないように感じられたことが、自分としてはとても嬉しい内容でした!回答頂いたメンバーの皆、ご協力ありがとうございました! まとめ 今回は私が1on1を実施する際に意識していることについて、紹介させていただきました! 最近では1on1を導入している企業が多く、1on1スキル向上のための本もたくさん出版されています。 弊社は比較的エンジニア間の年齢も近く、エンジニア組織としても大きくないため、そういった要因も含めて上手く1on1が実施できている側面もあると思います。 また、今回の執筆はブログとして外部公開することが前提のため、ポジティブな意見に絞られている部分もあると思っており、慢心せず自分との1on1がより有意義な時間となってもらえるように精進していきたいと考えています。 (といいつつ、メンバーの皆に良いFBをたくさん貰って素直に嬉しかったです!いつもありがとう!) 一般的にもよく言われている内容と重複してる部分も多いと思いますが、少しでも今後の1on1改善の参考になれば幸いです!
アバター
はじめに リプレイスの背景 旧ETL基盤の構成 課題感 転送時間 コスト 汎用性 新ETL基盤 構成 Step Function AWS Glue Job AWS Lambda 成果 転送時間 コスト 汎用性 まとめ はじめに こんにちは!スマートキャンプエンジニアの中田です。 直近で、BOXIL SaaSのDBのデータをBig Queryへロードするために利用していたETL基盤をリプレイスし、運用コスト・転送時間を改善しました。 旧基盤 新基盤 運用コスト(料金) 約 $750/月 約 $70/月 転送時間 約 1時間 約 10分 本記事では、そのリプレイスの背景や内容についてお話できればと思います。 リプレイスの背景 旧ETL基盤の構成 弊社のデータ分析基盤はもともと以下の画像のような構成になっていました。 データ分析基盤の構成 今回リプレイスしたETL基盤は、画像真ん中あたりに位置するEC2(Digdag + Embulk)の定期処理サーバーです。 c4.large サイズのインスタンス * 4台で処理対象のテーブルを分割して請け負っており、それぞれが毎時00分に定期処理されるような構成になっています。 Big Queryには全件洗い換え方式で実行ごとに最新日付でシャーディングテーブルが作られます。 これは、DBの状態を時間軸で辿れるようにしておくための運用です。 課題感 運用していたETL基盤には大きく以下の3つの課題感がありました。 転送時間 1つ目は転送時間の問題です。 旧ETL基盤で、BOXIL SaaSのDBのデータをBig Queryにロードするまでの処理に1時間弱の時間を要していました。 そのため、定期処理の頻度はhourlyとなっています。 転送時間を短縮すると、実行頻度も上げられます。 Big Queryに送られたデータはBIツールを通してビジネスサイドで分析に利用しているため、最新のDBが分析に利用できるまでのラグを短縮するためにも転送時間を改善したいなと思っていました。 コスト 2つ目はコストの課題です。 コスト(料金) BOXIL SaaSのDBのデータ量は約5GBです(一部転送対象に含めていないログテーブル等は除く)。 ETL処理を行なうために c4.large タイプのEC2インスタンスを4台稼働させていたため、月々$750ほどの料金がかかっていました。 データ量が膨大なわけでもないため、もっと安価に運用可能な方法を検討したいなと思っていました。 コスト(時間) リソースの枯渇など継続運用によるサーバー起因の問題が発生した場合にはサーバーに入り調査・解決する必要がありました。 一時期は高頻度で上記のような問題が発生しており、管理にコストがかかっていました。 また、複数台のインスタンスで処理対象のテーブルを分割しているため、処理が追いつかず台数を増やす場合には、新たに設定してインスタンスを立てる、テーブル分割の設定ファイルを都度チューニングする、といった手作業でのセットアップが必要で手間でした。 汎用性 3つ目は汎用性の問題です。 旧ETL基盤は上記の通りBOXIL SaaSのDBにのみ適応されていました。 一方で弊社には複数のプロダクトが存在します。 個別にデータ分析のための仕組みを持つプロダクトもあるものの、ETL処理の流れをBOXIL SaaS同様に一貫して行いたいという要望がありました。 また、新規のプロダクトができた際にもなるべく工数をかけずにデータ分析基盤を整えたいため、ETL基盤にも汎用性が求められます。 しかし、旧基盤はIaCされておらず、BOXIL SaaSに閉じた作りになっていたため、各環境に反映するには同様の基盤を手作業で組み直す必要がありました。 新ETL基盤 前述の課題感を低減するべく、新たに作り直したETL基盤が以下になります。 構成 新ETL基盤の構成 新基盤は上記のサーバーレス構成で作成しました。 上記の構成はTerraformでコードベースで管理しており、Moduleとして切り出しているため各WorkspaceのコードでModuleにパラメーターを注入して利用することで汎用可能となっています。 全体の流れと各処理の役割について簡単に説明します。 Step Function ワークフロー 画像の通りAWS Step Functionsのステートマシンでワークフローを作成し、以下の流れでステップ実行しています。 Glue Jobで任意のストレージ -> S3にデータ転送 LambdaでS3 -> Cloud Storageにデータ転送 LambdaでCloud Storage -> Big Queryにデータ転送 ワークフローはCloudwatch Eventでルールに基づいてスケジュール実行するよう設定しています。 AWS Glue Job Glue Jobでは任意のストレージからデータをロードして加工後、S3に書き込む処理を行っています。 S3に書き込むファイルの形式は旧基盤でJSONだったのに対し、新基盤ではファイルサイズが小さく・読み込み効率の良いParquetを採用しました。 環境変数以外では、このジョブスクリプトのみTerraform側で可変に設定できるようにしており、以下の処理を環境に合わせて書き変えます。 MySQLやPostgreSQL、Salesforce API等読み込み対象のストレージへの接続処理 読み込み対象から排除したいテーブルの指定、データの加工処理 AWS Lambda Lambdaでは以下の処理を行なう2つの関数を定義しています。 Amazon S3 -> Google Cloud Storage Google Cloud Storage -> Big Query Lambdaには転送以外の処理は持たせず、Storage to Storageのバケツリレーのみ行っています。 ランタイムはどちらもGoで、速度を上げるためにそれぞれデータの書き込み部分はgoroutineを使って並列処理するようにしています。 成果 新しいETL基盤の構築により、旧基盤と比較して以下の改善ができました。 転送時間 実行時間 BOXIL SaaSのDBのデータの転送で約1時間 -> 約10分に改善できました。 現状、転送頻度はこれまで同様にhourlyのままで設定していますが、環境ごとにCloudwatch Eventルールのcron式を調整できるようにしているため頻度を倍にも調整可能です。 コスト コスト(料金) BOXIL SaaSのDBのデータの転送で月当たり約$750 -> $70に改善できました。 旧基盤では常時稼働していたサーバーが、新基盤ではサーバーレスにスポットで実行されるようになり、大幅にコストを削減できました。 コスト(時間) サーバーレス構成にしたことで、サーバーの継続運用による問題で手を焼くことは少なくなりそうです。 また、Terraformを利用して汎用性を考慮してコードベースで管理しているため、各環境でこのETL基盤の構成を再現することも容易になりました。 別環境での基盤構築にかかる工数も削減できていると言えそうです。 汎用性 Terraformで構成をModuleに切り出しているため、各環境下で汎用的にETL基盤を再現できます。 環境ごとに作成するようにしているGlue Jobのスクリプトの記述も、ストレージタイプが同じ場合はほぼほぼ同様のコードで問題ないため、新しいタイプのストレージを利用したい場合のみ接続部分の記述に少し工数が取られそう、というくらいの肌感です。 まとめ いかがでしたでしょうか? 今回はETL基盤のリプレイスについてお話ししました。 ETL処理を実現する方法は多様にあるため、どのサービスをどう組み合わせて作るのが効果的かなと悩みます。 構築にあたってはいくつかの方法を検討したうえ、効果を比較していく過程にもっとも時間がかかりました。 構築をご検討の際に本記事を一例として参考にしていただけますと幸いです。 最後まで読んでくださりありがとうございました!
アバター
挨拶 こんにちは。 BALES CLOUD エンジニアの井上(エース)です。 BALES CLOUDは最近アナリティクス機能をリリースしました。この機能は、ユーザーのこれまでのコールやメールのデータをユーザーの好きな形で分析できるものです。 トップページの機能一覧の右上に表示されています。 この機能は Sisense の埋め込み機能を利用しています。SisenseはLookerやTableauのようなBIツールの一つですが、アプリケーションへ埋め込みが特に想定されているようで、非常に簡単にアナリティクス機能をBALES CLOUDに組み込むことができました。 話は変わるのですが、 前回の私の記事 ではLookerをスマートキャンプのデータ分析基盤のBIツールとして利用していることについての記事を書きました。ここで私はLookMLを使って開発をしていました。 どちらも 第三世代BIツール として知られているBIツールですが、2つとも触ってみると、開発者視点で違いが見えてきました。今日はその違いについて語らせて貰えればと思います。 前提 弊社では各ツールを以下の用途で使用しています。 Looker 弊社のデータ分析のためのBIツールとして Sisense 弊社プロダクトのデータ分析機能として そのため重点的に触っている機能が多少異なります。記事にするうえで調査はしていますが、抜け漏れがあった場合はコメントなどでお知らせくださればありがたいです! また、一人のエンジニアとしての観点となるので、マネージャー側の視点(例えばコストなど)についてはスコープ外とさせていただきます。 加えて、この記事は企業としてどちらかのツールを賛美するような記事ではありませんのでご注意ください。 ドキュメント 両者の違いをもっとも感じたのがこちらです。開発をするうえでドキュメントが充実しているかはツールが持つ機能性と同じ程度重要だと私は考えています。 Lookerは 公式が用意しているドキュメント が豊富です。またBIツールとして現状メジャーな選択肢ということもあってユーザーが多く、 コミュニティ にも有用な情報が載っています。公式ドキュメントは日本語もあるので読みやすいです。 Sisenseは機能の豊富さに ドキュメント がまだついてきていない印象です。公式ドキュメントは存在するものの足りない部分が多く、特にプラグイン開発をするうえで困りました。また公式ドキュメントは日本語には非対応なので、そのあたりも辛いときがあります。 コードの再利用性 LookerはLookMLという独自言語を利用することでコードの再利用性を高めつつ、非常に柔軟にクエリを書かせてくれます。Lookerでは基本的にデータの定義が分散することは起きづらいですし、それによってデータ定義をDRYにできます。 Sisenseはデータモデルをインポート・エクスポートできます。これによって同じコードを書くことは基本的に避けられるものの、別々のモデルで同じデータ定義を使いたい、などの場合は辛いかもしれません。 データモデルの構築の容易さ LookerはLookML上で開発が完結するため、あるモデルを作る場合はLookMLを書いていく必要があります。 Sisenseのデータモデルは基本的に図を使って行います。どのテーブルをインポートするのかを定義し、それがどのように紐づくのかをコードではなくほとんどGUI上で行います。特にリレーションの定義がドラッグアンドドロップでできて作業効率が高いです。またこの定義の仕方は非常に直感的で、かつあとで見たときにどれがどれに紐付いているのかがすぐに分かります。モデル構築の容易さについてはSisenseが優れていると感じました。 https://sisense.gaprise.jp/solution/sisense-analytics デプロイのパイプラインの構築 LookerはLookMLをGit管理できます。これによって、Prodに上げる前に自分のブランチで動作をチェックしたり、プルリクを出してレビューを受けたりできます。これによってデプロイが手間なく安全に行なえます。 Sisenseにはバージョン管理機能は現状ありません。本番に上げる前に確認などしたい場合は、モデルのインポート・エクスポート機能を使うなどする必要があります。ちなみにエクスポートされたファイルを自前のリポジトリでバージョン管理するなどできますが、Lookerのようにネイティブにバージョン管理が組み込まれているものではありません。 クエリのデバッグ 地味ながら大変重要なのが開発していくうえでのデバッグの容易さです。LookerではLookMLから自動生成したSQLを見ることができます。これを見ることで自分のLookMLの誤りに気づくことができます。何度これに助けられたかわかりません。 SisenseはJAQLという言語で動いており、SQLを見ることができません。代わりにクエリ発行時にどういったリレーションでデータが取得されたかを確認できます。ただこれはSQLに慣れているエンジニアであるほど理解しづらいものだと感じました。見方もちょっと独特なので、慣れるまでは時間がかかるかと思います。 https://community-old.sisense.com/hc/en-us/community/posts/115007013548-JAQLine-Plugin-Visualize-Widget-s-Queries クエリの高速さ Lookerは基本的にライブ接続(自前でデータを保存せずDBにクエリを叩きに行く方式)であるため、クエリ発行時にBigQueryなどのデータソースにクエリを投げ、その結果を表示します。 Sisenseはライブ接続とElastiCubeの二種類がデータソースとして選べます。 ElastiCubeはSisense独自の高性能な分析データベースで、ビジネスインテリジェンスアプリケーションで必要とされる大規模なクエリに耐えられるよう特別に設計された超高速データストアを搭載しています( 公式 より)。 この説明に引けをとらず、たしかにElastiCubeは非常に高速に動作します。300万件程度のテーブルにさまざまなテーブルをJOINしても結果が出るまで1秒もかかりません。動作が早いというのはユーザーはもちろんですが、開発者としても開発するうえで時間を大幅に節約できるので助かります。 一方でLookerはキャッシュ機能が非常に高機能で、細かく動作を決めることができます。そのためLookerのクエリがすべて遅いわけではなく、キャッシュ戦略次第です。ただそれを差し引いてもSisenseの高速さは魅力です。 注意点として、ElastiCubeは毎回DBからデータを取得し、サーバーにビルドするという作業が発生します。1時間に一回ビルドするなどスケジュールを決められるので、このあたりは考慮が必要です。ちなみにBALES CLOUDではデータ量がまだそこまで多くないため、このビルド作業はあまり気になっていません。このあたりはプロダクトのデータ量次第ですね。 データモデル設計 LookerはLookMLでそれぞれどのテーブルがどのようにJOINされるかを定義したり、あるテーブルには特定のテーブルのJOINが必須であることを定義(required join)できたりとデータモデル設計に柔軟さがあります。 Sisenseはスタースキーマ(スノーフレークスキーマ)をベースにしたデータモデル設計を前提としている感覚があります(スタースキーマについては こちらの記事 が非常に分かりやすいです)。例えばSisenseでは、クエリ発行時、 JOINパスが自動で決まります 。つまりテーブルAからテーブルBへのテーブルの結合が、テーブルC経由でもテーブルD経由でもできるようにしているときにどちらを経由するかを指定できません。これにより問題が発生します。 分かりやすい例でいうと、行ごとにtenant_idを持つシステムです。下記のような場合、usersからtagsの情報を取ろうとすると、user_tags経由かtenants経由かという二択が存在することになります。当然user_tags経由が正しいのですが、設計上はtenants経由でもデータは取得できます。 このような場合に、勝手にJOINパスが決められる事による問題が発生します。つまりtenants経由でデータが取得されて、意図しない結果となる可能性があります。 これを避けるのであれば、スタースキーマ的な設計をする必要があります。 tenantの情報は冗長化されてそれぞれディメンションテーブルに格納されています。この設計だとusersからtagsへのルートは一つしかないので、さきほどのような問題が起きません。 かなり簡略化しているのですが、イメージが伝われば幸いです。 データウェアハウスを設計するうえでスタースキーマをベースに作ると、ディメンジョンとファクトが分かれているため利用しやすいというようなメリットが多くあります。このような作りを意識することが必要になるため、結果としてSisenseを利用することがより良いデータウェアハウスを作ることに繋がるという考え方もできます。 アプリケーションへの組み込み Sisenseはアプリケーションへの組み込みが強く想定されているというのが随所に感じられました。たとえばSisenseでは埋め込み用に iframe、Embed SDK、Sisenes.JS の3つの方式が用意されています。Sisense.JSがもっとも高機能で、ウィジェット単位でカスタマイズができます。iframeの埋め込みも簡単にできます。ドメイン制限やCORSの設定やSSOはもちろん対応しています。こういったこともあって、BALES CLOUDでは機能要望に合ったものをあまり開発工数をかけることなく作ることができました。 Lookerの埋め込みについては実際に業務で触っていないのですが、iframeによる埋め込みが可能です。パブリック、プライベート、SSO埋め込みができます。いずれも簡単に実装ができそうですが、Lookerについては APIを通してデータ取得する ことができて、かなり高機能なので、こちらを使うパターンが多いかもしれません。 Sisenseについてもう一つ特筆したいのが Row Level Securityにネイティブ対応 していることです。企業アカウントごとに見えるデータを分けたいといった要望はアプリケーションへの組み込みでよくあると思いますが、Sisenseは非常に簡単にこれを実装できます。こういう点もアプリケーションへの組み込みを前提としているプロダクトならではだと思います。ちなみにLookerでも User attributesとaccess_filterを使えば 実装は可能ですが、Sisenseに比べると少し工数はかかりそうです。 総括 さくっとアプリケーションに組み込みたい、といった場合はSisenseが適しているかと思います。データモデルの構築は基本的にはほぼノーコードでできますし、iframeによる組み込みやRow Level Securityの対応などもあって、アプリケーションへの組み込みの初動を強力にサポートしてくれます。 一方でドキュメント性やバージョン管理、コードの品質管理、デバッグ、その他総合的な機能性でいうとLookerのほうがやはり優位かと思います。特にドキュメントが整っているのは本当に助かります。Git管理ができるのも開発者としてとても助かるポイントです。 最後に、色々と語ってしまいましたが、まだまだBIツール初心者なのでご指摘などありましたらコメントなどでお待ちしております! ご一読ありがとうございました!
アバター
あいさつ こんにちは!スマートキャンプ開発エンジニアのハヤシです。 私は 入社エントリ でも述べたとおり、コミュニケーションスキルの向上を目的にスマートキャンプに入りました。 約10ヶ月ほどBOXIL SaaSチームで働く中で、「入社当初と比べて結構変わったな〜」と思うことが増えてきました。 前回は 技術的な記事 を書いたのですが、今回は、思いっきりポエムに振り切って入社前と比べてどう変わったかを諸々振り返っていこうかなと思います!極めて個人的な話になってしまうのですが、よかったら見ていただけると嬉しいです!! あいさつ 自分自身について 入社半年ぐらいまで ぶち当たった壁 分からなくても相談・質問できない 想像以上にコミュニケーションが多く、疲弊する 人前で話すときに上手く話せない、言葉が詰まる なぜコミュニケーションが苦手なのか 苦手だと思っている理由 どう対応したか 思考・行動を変える 運動する 疲れたらとにかく寝る 人それぞれが自分の正解を持っているという感覚を持つ 人にお願いごとをしてみる 過去の失敗を振り返ってみる 人との接し方を変える 意識的にテキストでコミュニケーションする 相手に思っていることちゃんと伝える 反応を気にしない 感謝を伝える 意識・行動が変わった結果 会社の行事を楽しめるようになった チームの成功に目が向くようになった 成果 今後に向けて 自分自身について まず、入社時点でのコミュニケーションスキルを書いていこうと思いますが、我ながら本当に低かったと思います。 万年帰宅部で友達もほぼいない(ゲームが友達でした) 大学時代、コミュニケーション系の必修科目の単位を「人前で話すのが嫌すぎる」という理由でわざと落とす 社会人になるが、取引先とのMTGでは緊張で一言も話さず終了することも日常茶飯事(ニコニコするように努めてはいた) 新卒で入った会社で、話せなさすぎて取引先から担当者をクビになる。 エンジニアとしてもチーム開発の経験はほぼなし。誰とも話さず一日が終了することもありました。 このように、人と接することに向き合わないで生きてきて、10代〜20代前半までは問題なく生きてこれたのですが、 エンジニアとしての経験を積んでいくにつれて、コミュニケーションを必要とする機会が増え、うまくいかないなと思う日が増えていきました。 特にフロントエンド開発では、実装する際に確認しないで作業を進めてしまうことが多々あり、結果的に実装時間が増えてしまい残業が度々発生してしまっていました。 このようなことが重なり、コミュニケーションに苦手意識がある自分に限界を感じてきたため、その部分で成長できる会社に行こうと決めてスマートキャンプに入社しました。 入社半年ぐらいまで スマートキャンプは想像以上にコミュニケーションが活発な会社でした。 上述したとおり、コミュニケーションに強い苦手意識を持って入社した最初の半年間は全く環境に慣れず、壁にぶち当たりまくりました。 今まで人と接することを避けてきたツケが回ってきたようでした。 ぶち当たった壁 分からなくても相談・質問できない 想像以上にコミュニケーションが多く、疲弊する 人前で話すときに上手く話せない、言葉が詰まる 分からなくても相談・質問できない それまで個人プレーで開発していたのもあり、ある程度のオンボーディングが終わった後は、独力で実装を進めないといけないという思い込みがありました。 仕様の部分で詰まっても、相談するのを躊躇っていて、Slackでチームメンバーに質問する際にも「こんな低レベルな質問していいのかな」とか「そもそも質問するのがめんどくさい。自分で頑張ろう」と考えて開発に支障がでてしまっていました。 想像以上にコミュニケーションが多く、疲弊する BOXIL SaaS開発チームでは、以下のとおり多くのコミュニケーションの場が存在します。 今までの社会人生活で最低限のコミュニケーションしか行っていなかった自分にとっては、あまりにも人と話さなければいけない機会が多く疲弊していました。 デイリーレポート(毎日) 日報のチャンネルです。今日やったこと、感じたことなどを全ての社員が投稿していて、お互いに見ることができます。 企画朝会(ほぼ毎日) 企画チームとスプリントタスクの進捗を確認し、企画されたタスクのポイントづけを開発チームメンバーで行なう場です。せーのでタスクに対するポイントを出し合って、ポイントが一致しなかった場合は、どの部分でポイントが増えそうかなどを議論する場でもあります。 スプリントレビュー(毎週) ビジネスサイドのメンバーも含めて開発した機能を関連部署にお披露目する場で、毎週開発した機能をドキュメントにまとめて発表しています。 レトロスペクティブ(毎週) チーム開発するうえで起きた問題を振り返りする場で、そもそもMTG多くて開発効率落ちてね?みたいなのも議題に上がり、水曜日がNo MTG Dayになるなど、開発に関する改善がここで話し合われます。 最近のワイ(週1) 毎週担当者が週替わりでやったこと・ハマったこと・これからやることを発表する会、プライベートな話をする人も多いです。 プロジェクト版最近のワイ(2週間ごと) プロジェクトごとでやっていること、詰まっていることなどを共有し、異なるチーム間でのコラボレーションを促進する会です。 OST(月1) Open Space Technologyの略でいくつかのテーマについて時間を区切って技術に関する議論をする会です。 STT(3週間に1回) 「最近気になる技術・技術記事・ニュース」を紹介する会です。 メンバー・上長と1on1(隔週) 唐突に入ることもあります。 SMARTCAMP AWARD(年2回) 半期ごとに個人の成果を全社員で共有し合う会です。他部署の施策や成果を知れる場でもあります。 勉強会(隔週) Reactの勉強会とかを皆で集まってやっていた Gatherに常駐(毎日) ZoomやDiscordではなくGatherをリモートワークのコミュニケーションツールに選んだ理由 入社してすぐの時はDiscordを使っていたので、開発メンバー全員が同じチャンネルに常駐する形で運用していたのですが、上記の色々な施策も相まってコミュニケーションが密接すぎると感じてしんどかったです。 その後、gatherに移行となってある程度緩和されましたが、それでも当社は常に誰かに見られながら仕事をしなければならない感覚があり、慣れませんでした。 また、最初の2ヶ月ぐらいは、MTGがあるたびに緊張して臨んでいて、業務後は何もできないぐらい疲れて、「どうしてこんなに人と話すと疲れるんだろう?」と毎日弱音ばかり吐いて落ち込んでいました。 特に企画朝会やスプリントレビューでは、司会になるとさらに緊張感を持った状態で話さなくてはならず、疲れることが目に見えていたので恐怖でしかありませんでしたが、何度も何度も自分に「逃げちゃダメだ」と言い聞かせて参加していました。 人前で話すときに上手く話せない、言葉が詰まる これはもうある程度わかりきっていたことではあるのですが、自分でも驚くぐらい人前で話せなくてびっくりしました。一番最初に司会になったときは、どうやって話していいかわからず、全く周りが見えない状態で早口で吃ってたのを記憶しています。 1on1等でチームメンバーと話すときも、相手の会話にかぶせ気味で話し始めてしまうことも多く、色々と歯車が合わずギクシャクしていました。 そのほかにも、MTG中に別の業務をしていて人の話を聞いていなかったり、目先の作業に集中しててMTGをすっぽかすなど、周りのことを考えてない相当ヤバいやつだと思われていたと思います。 このように半年間ぐらいは、苦手なことばかりで全く楽しくなく、自分としてもチームとしても完全にマイナスからのスタートでした。 なぜコミュニケーションが苦手なのか 自分にとってスマートキャンプの環境が想像以上に過酷だったので、一時期は辞めることばかり考えていました。高い志を持って入社したのに、全く変われず終わってしまう、と焦りました。 そこで、コミュニケーションが苦手だと思っている理由をあらためて考えて、どう対応したら解決しそうかを考えました。 苦手だと思っている理由 人前と話すときに緊張する、どう見られているかが心配。 頼みごとをしても拒絶されるのが怖い。 相手の言っていることを覚えられない、すぐ理解できない。自分は頭が悪いという思い込み。 自分のいうことは正しくないのではないかという不安。 自分自身について深く考えるまで、単純に業務的なコミュニケーションが苦手なだけかと思ってたのですが、根底には自己認知に問題があるから苦手なのではないかということが見えてきました。 これらを改善しなければ当初の目的は達成できそうにないなと考え、まずはそこから変えていこうと思いました。 どう対応したか 大体苦手な理由はわかってきたので、自分ができること・できないことを明確にして行動を少しずつ変えていきました。 これらを通して、仕事や対人関係にも良い影響が出てきました。 思考・行動を変える 人との接し方を変える これらの行動を具体的に紹介していきます。 思考・行動を変える コミュニケーションの苦手意識の原因が、低すぎる自己肯定感にあるとわかったので、自己肯定感を上げるための努力しようと思いました。 正直これを変えるのが難しかったですが、以下のように行動する事が自分には効果がありました。 運動する 疲れたらとにかく寝る 人それぞれが自分の正解を持っているという感覚を持つ 人にお願いごとをしてみる 過去の失敗を振り返ってみる 運動する 筋トレするのが良いと聞いたので、今まで身体を動かすのは全くしてなかったのですが、1日1回10分間の軽い筋トレを始めました。 これを習慣化することで、小さな成功を積み重ねる達成感と、集中力を鍛えることができました。程良く疲れる事で眠りも深くなったような気がします。 疲れたらとにかく寝る 自分は眠い時にネガティブ思考になる事がわかったので、とにかく最低9時間は寝ることを徹底しました。 ポイントは負の感情が湧いてきたと同時にとにかくすぐ寝る事です。タスクが残っていたとしても、明日起きてからやると決めて寝ました。 本当に思い立ったらすぐに寝ていたので、業務後の19時とかに就寝して朝5時に起きるみたいな事も多かったです。 これらを行う事で、大抵の悩み事も次の日にはちっぽけなものだと考える事ができるようになり、変に卑屈になることも減っていきました。 人それぞれが自分の正解を持っているという感覚を持つ 「勉強の問題のように誰かが正解を持っている」と思っていたのですが、人それぞれが自分の正解を持っているという考え方をするようにしました。 暴論のように思えるかもしれませんが、それからは「自分が間違えてたとしても、思ったことを言ってもいい」と思えるようになり、本当に気持ちが楽になりました。 今まで自発的にコミュニケーションが取れなかったのも、自分が言っていることは間違えているのではないか、という思い込みが原因となっていたことに気がつきました。 コードレビューで指摘されたときも、「自分のコードも正解だけど、提案されたコードの方が綺麗だし、より正しいコードだからそちらを採用しよう」という思考になり、自分が完全に間違えているとは思わなくなりました。 人にお願いごとをしてみる ある本に、頼まれごとを断られる確率を低く見積もりがちだという話が書いてありました。 その本によると、頼まれる側が遂行を強制されていると感じるような頼み方でない限り、実際には依頼を引き受けて貰えるケースが多いと書かれており、人への依頼に高いハードルがあった自分を変えてくれました。 実際にSQLクエリ作成タスクをSQLに詳しい人にお願いしたり、自分がした実装についてコメントくださいと言ったときも、依頼された人は案外快く引き受けてくださって、逆に自分が頼まれる側になった場合にも精一杯答えたいという気持ちになりました。 結果として個人の負荷も下がり、開発のパフォーマンスも上げることができました。 過去の失敗を振り返ってみる 私は、デイリーレポートというチャンネルに日報として毎日の成功・失敗を書いているのですが、これらをあえて振り返ってみると、失敗した理由や内容をロクに覚えていないことが発覚しました。 自分の記憶力のなさに呆れてしまいますが、どうせすぐ忘れてしまうなら、好き勝手やってしまえと開き直ることができました。 人との接し方を変える 自分の得意・不得意を踏まえて、今より状況を良くするために、以下のことを実践しました。 意識的にテキストでコミュニケーションする 相手に思っていることちゃんと伝える 反応を気にしない 感謝を伝える 意識的にテキストでコミュニケーションする 自分は、相手が言っていることをすぐに理解することが不得意なので、意識的にSlackなどのテキストコミュニケーションで行なうようにしました。 テキストで会話することによって、用語の意味等を調べながら理解する時間ができ、記憶力が低い自分でも文章を咀嚼しながら返信できるので、相手に考えを伝えるというゴールは達成しやすくなりました。 どうしても音声やビデオでコミュニケーションが必要な状況になってしまったら、例え相手が顔を映してたとしても、自分は顔を映さないで話すようにしました。 これは、自分が「見られること」に対してストレスを感じやすいことへの対策で、この対策により発話のみに集中できるようになりました。 スプリントレビューなど多くの人の前で発表しなければいけない状況においても、これを徹底したことで、「あれ、俺意外と話せるじゃん!」と自信がつきました。 相手に思っていることちゃんと伝える 自分が考えていることを言語化しないで放置してしまうことが多く、本来議論すべき場面でも波風が立たないように逃げてしまっていました。 例えば、なにか自分が起こした問題について責められたときには、自分がすべて悪いとすぐ決めつけて、完全に思考停止して謝っていました。 そこで、自分に非があると感じていたとしても、それが起きた理由をしっかりと伝えるようにしたところ、意外にも理解してもらえることが多く、気持ちを伝えることの重要性を感じました。 今まで謝りっぱなしだったのが、会話が往復するようになったおかげか、人間関係も一気にうまくいくようになって自己肯定感も上がりました。 反応を気にしない 結構気にしいな性格なので、自分が発言したことに対してあれこれ考えてしまいます。「あの時のあの表現は良くなかったな」とか「Slackで投稿しても誰からもリアクションこねええ」とかで一々引きずってしまっていたのですが、自分が発言したことに対して一切何も考えないようにしました。 反応を気にしないようにしてからは、無駄に悩むことがなくなって、目の前のことに集中できるようになりました。 感謝を伝える これは単純ですが、「ありがとうございます」を言いまくりました。ありがとうと言われるのが嫌いな人はよっぽどひねくれた人でない限りいないと思いますが、とりわけ自分が相手になにか相手に恩恵を与えたときにも積極的に感謝を述べるようにしました。 タスクについて質問されたときも、コードを一緒に眺めたときも、相談にのったときも、「ありがとうございます」とひたすら口癖のように言いまくることで、「いろんな人に感謝を感じている俺エラい」と一種の自己陶酔?に近い感覚になり、自己肯定感を高めることができたと思います。 これらのことを意識し始めてから、少しずつ自分が良い方向に向かっていることを実感していきました。 意識・行動が変わった結果 会社の行事を楽しめるようになった あんだけ苦痛だったあらゆる行事が全く苦ではなくなりました。慣れたからというのもあるかと思いますが、身の回りで起きている問題に対して皆で立ち向かうのってステキやんって思えるぐらいまでに考え方が変わりました。 昔は、ハードスキルばかりに目が行っていて、ソフトスキルをかなり軽視していたのですが、今はその比率が五分五分ぐらいになり、バランス良くありたいよねって考え方に変わりました。 デイリーレポートチャンネルでも、ちょっとエモいことつぶやいたら、スタンプが多くついて嬉しくなったり、反対に散々な日のときにも励ましの言葉をもらったりして、スマートキャンプのウェットなコミュニケーションも楽しめるようになってきました。 チームの成功に目が向くようになった BOXIL SaaSチームメンバーの異動や退職が重なり、自分が入社時には11名程いたチームメンバーも、正社員3名程に減少したことで、自分に求められることが変わってきました。 並行してBOXIL SaaS質問箱プロジェクトも発足し、エンジニアリソースが分離することになりました。どんどんチームメンバーが減っていくなか、一時的にチームのマネージメントを任されることになりました。 入社当初は自分自身に精一杯で、他メンバーのことを考える余裕なんてなかったのですが、地道に自分を変える行動を続けたおかげか、チームのことを考えられるまでになりました。 毎週のスプリントタスクの管理や、業務委託メンバーとの相談、進捗管理、スプリントレビューの発表も自分から率先して行なうようになり、周りを見て行動できる場面が増えていきました。 もちろん、マネージメントすることについて全くの未経験だったので、上長にやり方などを聞きながら進めたのですが、それすらも「昔だったらできてなかったよな・・・」と思うので、その部分ではかなり成長できたのかなと思います。 成果 毎年2回開催されるSMARTCAMP AWARDで2022年上期のファイナリストになることができました。 これは全社員で半期ごとに成果を発表しあうイベントなのですが、自分はこれと言って突出した成果出してないしなぁと考えていたので、ファイナリストに選ばれたときはびっくりしました。 惜しくも本選で破れてしまったのですが、自分が今までやってきたことは間違いではなかったと感じ、報われた気持ちになりました。 今後に向けて ここまですべて自分との戦いに終始していたのですが、コミュニケーションという難敵を倒せそうだと感じた今、あらためて技術者としての勉強を深ぼってやっていきたいですね。 フロントエンドがやっぱり好きなので、イチから設計できる案件や、モダンな技術に積極的に触っていきたいです。 そして何より、今よりもっともっと周りを巻き込んで、良いプロダクトを作れるようにチームを引っ張って行けるように頑張っていきたいと思っています! 今回は長々とポエムに全振りしたので、次回はゴリゴリ技術系のブログを書こうと思います! ここまで読んでいただきありがとうございました!
アバター
こんにちは!! スマートキャンプでエンジニアをしている吉永( @__GGEasy )です! 自己紹介記事はこちら 前回の記事はこちら 私は現在、スマートキャンプの主力サービスであるBOXIL SaaSの開発にフロントエンド、バックエンド問わず携わっています。 今回は、弊社で新規サービスとしてリリースしたBOXIL SaaS質問箱(以下SaaS質問箱)にて、React.js(以下React)を私の主導で採用しました。 この記事では、フロントエンド整備に至った経緯や、今後のBOXIL SaaSにおけるフロントエンドの技術的な展望についてお話します。 BOXIL SaaSのフロントエンドで抱えていた課題感 さまざまな技術が同居している Vue + Atomic Designでの課題 構成変更の検討 どのようにフロントエンド構成を整備したのか SaaS質問箱のフロントエンド技術選定 React + TypeScript Recoil styled-components react-hook-form react-router-dom ディレクトリ構成の決め ディレクトリ構成の前提となったお話 最終的なディレクトリ構成 components uiParts pages ディレクトリ構成を見直してよかったこと この構造のデメリット 今後の改善プラン フロントエンドの一本化 WorkSpaceの活用 まとめ BOXIL SaaSのフロントエンドで抱えていた課題感 さまざまな技術が同居している BOXIL SaaSは直近できたプロダクトではなく、何年も前から開発保守されてきています。そのためフロントエンドの採用技術は、以下の技術の組み合わせを使用していました。 Vue.js + TypeScript(Vueのバージョンは2.x、以下Vue, TS) Vanilla JS CoffeeScript(以下Coffee) Coffee + Vue Coffee + jQuery というようにページごとにさまざまな技術が同居している状態です。 以前、decaffeinateによるCoffee撲滅も検討しましたが、吐き出されるJSがES6になる問題にぶつかりました。 Uglifierの影響でコンパイルが通らない問題は解消しましたが、BOXIL SaaSのターゲットユーザーの属性を考慮すると、Internet Explorer対応の優先度が高くES6の記法が使えません。 そのため、Internet Explorerのサポートが終了した直近まではCoffeeを消す作業を中断していました。 webpackであれば簡単にトランスパイルができますが、現状すべてをwebpackに任せているわけではないので、decaffeinate -> ES5の記述に手動で変換する必要が出てきてしまいます。そこにコストを掛けるのは、もったいないよねというチームの判断です。 今回Reactを採用する過程でVueへの一本化も考えましたが、直近あったVue2.xからVue3へのアップデート対応にかなり破壊的変更があるため、2系と3系の同居ができない以上あまり使い続けるメリットを感じていませんでした。 Vue2.xと3の同居に関する検証結果も記事にしているのでぜひご覧ください。 Vue 2.xとVue 3を共存させようと思ったけどダメだった話 Vue + Atomic Designでの課題 これまで使用していたVueではAtomic Designを採用した共通化を重要視したコンポーネント設計をしていました。 詳細は後述しますが、現在BOXIL SaaSにこれといったデザインシステムがありません。 そのため、スタイルは同じだが挙動が違うといった問題や、挙動は同じだがスタイルが違うと言った問題が起こりました。 そうしているうちに、スタイルが違う場合はdeepメソッドで親コンポーネントから上書きするなど、可読性や保守性にかなり問題がある作りになってしまった部分が散見されました。 また、Atomic Designの通りにコンポーネントを作成した後、その後の保守で特にMoleculesの粒度などが見直されず開発され続けた部分がありました。 その部分はかなり肥大化してしまい、MoleculesとOrganismsの境界線が不明確になるなどの問題をかかえていました。 Atomic Design以外で良さそうなコンポーネントの管理手段になるものを探していたところ、以下のような記事が見つかりました。 Atomic Designをやめてディレクトリ構造を見直した話 弊社で困っていた部分とはまた違った理由でしたが、他社でもこのような動きがあるということがわかり、これをベースにカスタマイズしていくことにしました。 また、Coffeeのなかでnew Vue...といった記述をしている部分もあり、ここから仕切り直して開発するのは難しいよねといった気持ちもありました。 さらに、弊社の採用時にReactを使った開発を望む候補者が多いことから、これまでBOXIL SaaSで採用されていなかったReactの採用をしようといった声が上がっていました。 構成変更の検討 今年の2月頃、新規のサービス開発が始まるということで、弊社のエンジニアチームでも特に若手の3人が集められました。 私はそのなかでもフロントエンドの技術に興味を寄せていたため、その分野における技術導入や開発を任されました。 本件は新規で開発する部分が多く、既存の作りに引っ張られにくいことは分かっていました。 かつ仕様策定の期間からジョインしたため、仕様を考える傍らで新技術の検証期間を設けられそうだという話になりました。 質問箱のPMの方の記事はこちら 私は以前、BOXIL SaaSのwebpackの改善とReactの新規導入を試しています。もしよろしければそちらの記事もご覧ください! 若手エンジニアの俺がフロントエンドのビルドを早くしてReactも導入しちゃった話 どのようにフロントエンド構成を整備したのか 整備にあたって、まずはいくつか導入以前に存在しているフロントエンド課題の洗い出しや、社内での新規技術導入に対する温度感を一致させる必要があると感じました。 フロントエンド課題の洗い出しについては以前から積極的にやっていたこともあり、メンバー間である一定の意思疎通はできていました。 詳細に関しては割愛するため、上記に貼っている記事「若手エンジニアの俺がフロントエンドのビルドを早くしてReactも導入しちゃった話」を見ていただければと思います。 ここからは、SaaS質問箱の技術選定やディレクトリ構成などのルールを中心に紹介します。 SaaS質問箱のフロントエンド技術選定 ここからは、選定した技術で主要なものを紹介します。 React + TypeScript 先述した理由から、今回はReactを使用することにしました。 Next.js(以下Next)も採用候補にはあがりましたが、ログインセッション周りの処理の移行も含めるともう少し時間をかけて改修する必要があり、今完全に切り離すのは難しいといった判断の元見送りました。 SEO的にSPAでいいのかという話については、これまでVueで使っていたページでSEO的に特に問題なく検索流入が入っていたことや、そもそも検索流入を狙うサービスではないことから、特に直近問題になることはないだろうと判断しました。 また、当然といえば当然ですが、型は欲しいのでTypeScriptを導入しています。 OpenAPIをBOXIL SaaSのバックエンドで採用している点から、今回はAPIのリクエストやレスポンスの型の自動生成などもしてもらい、それをフロントエンドで使用しています。 Recoil 状態管理には今回Recoilを採用しました。 新しい状態管理ライブラリとして2年ほど前から話題になっており、かつすでに動作の確認などはできていたので少し思い切って採用しました。 styled-components CSS in JSにするかどうかという話も一瞬あがりましたが、結局採用しました。 今のところ特に問題なく動作していますが、パフォーマンスに今後影響してきたら見直すかもしれません。 react-hook-form フォームの動作や簡単なバリデーション周りの挙動を作るために使用しています。 react-router-dom できるだけフロントエンドはRailsから引き離して開発をしたかったこともあり、Railsでルーティングさせるのではなく、react-router-domを使ってルーティングさせることを決定し、導入しました。 ディレクトリ構成の決め ディレクトリ構成の前提となったお話 BOXIL SaaSチームでは過去、デザインシステムなどの導入を検討していた時期があります。 しかし、BOXIL SaaS本体のなかでも画面ごとにパーツの形が違ったり、細かい挙動が違うためデザインシステムと言った形で共通化するのは厳しいのではないかという意見がデザイナーから出ていたこともあり、断念していました。 また、ここ最近slim + scssで構成されていたページで、application.cssというすべてのCSSを読み込むことによるCSSによる名前被りや、無理なCSSの共通化による小さいスタイルの崩れが起きがちでした。 余分なCSSを読み込んでいるためパフォーマンス的にも良くないということも最近のCWV対応でわかりました。 その結果、最近ではpartialやcomponentが違うのであれば、都度CSSファイルを発行し、1ファイルに対して1CSSといったような構成になるようにしていました。 これはファイル数が増えてしまうデメリットはありますが、CWV対応で必要なCSSのみを読み込むようにした今、それはあまりデメリットとして感じられなくなりました。 共通化しない大規模アプリケーションのCSSの設計としては、以下のようなものがあり、実際に参考にさせていただきました。 https://ecss.benfrain.com/ 最終的なディレクトリ構成 上記を踏まえて、以下のディレクトリにしました。(一部抜粋) BOXIL ├ ...(Railsで使っているディレクトリ軍) └ frontend_react(今回作成したReact用のディレクトリ)   └ [Railsのコントローラー名]     ├ assets     │ └ ...(jpgなど)     ├ components     │ └ [ページ名]     │   └ [コンポーネント名]     │     ├ index.tsx(ロジック層)     │     ├ presenter.tsx(見た目)     │     └ styled.ts(CSSを書くとこ)     ├ uiParts     │ └ [コンポーネント名]     │ ├ index.tsx(ロジック層)     │ ├ presenter.tsx(見た目)     │ └ styled.ts(CSSを書くとこ)     ├ globalStates     │ └ atoms     │   └ [各種state].ts     ├ hooks     │ └ [hooks名]     │   └ index.ts     ├ layouts     │ └ └ ...(各種レイアウト)     ├ pages     │ └ [コントローラーのアクション名]     │   ├ index.tsx     │   └ styled.ts     └ routes     └ index.tsx frontend_react直下のディレクトリはRailsのコントローラー単位で切るモノリポ構成です。ディレクトリを跨ぎ利用する共通コンポーネントは基本作成していません。 今回で言えばfrontend_reactの下には質問箱を意味するconsultationsディレクトリを作成しました。 また、最近行われたカテゴリページの改善では、frontend_reactの下にcategoriesというディレクトリが作成されました。 さきほども言ったとおりデザインや挙動が違ったり、呼び出している色などもBOXIL SaaS内で一律で決まっているわけではなかったりするので、ButtonやTextFieldなども現状は都度作っています。 また、今回他と変わった構造になっているのはcomponentsとuiPartsなので、ここを重点的に解説します。 components このディレクトリの中身はreact-router-domで定義したページごとに発行しています。SaaS質問箱では投稿画面が/consultations/newというパスで定義されていますが、その場合は以下のようになります。   └ [consultations(Railsのコントローラー名)]     ├ components     │ └ [new(ページ名)]     │   └ [TestComponent(コンポーネント名)]     │     ├ index.tsx(ロジック層)     │     ├ presenter.tsx(見た目)     │     └ styled.ts(CSSを書くとこ) となります。 これはAtomic DesignでいうOrganismsにあたります。 このコンポーネントはページごとに共通化はせず、単独の物として動作します。 デザインは共通の形だったとしてもコピペした状態でページごとに切り出し、中身の処理だけが違うといったような運用にしました。 また、presenter層を導入することで、APIの通信やロジックが関わる関数の実装はindex.tsxに任せ、簡単なifや基本的なDOMの構成はpresenterに任せる作りにしています。 uiParts uiPartsはAtomic DesignでいうMoleculesやAtomsにあたります。 Railsのコントローラー名直下のページで使う、ButtonやTextFieldがここに入ります。 また、Atomic Designのように最小単位で切り出すというルールではないため、例えば同じデザインのタブがあるのであれば、ここに入れても大丈夫です。 最小単位として存在するというよりは、ここにあるものはそのページで共通パーツとして使えるよという意味合いで運用しています。 StoryBookなどは工数の都合上導入できていませんが、このあと導入する場合もこのディレクトりにあるコンポーネントが対象となります。 pages そのページのトップになるディレクトリです。 ページごとに発行され、componentsやuiPartsをまとめたりするのはこのコンポーネントになります。 ディレクトリ構成を見直してよかったこと ディレクトリ構造を見直した結果、以下のメリットが有りました。 まず、汎用性の高いコンポーネントかそうでないかという区切りだけになったため、これはAtomsだろうか...Moleculesだろうか...といったような悩みが少なくなりました。 Moleculesに関しては改修の結果汎用的じゃなくなったとしても、Moleculesフォルダの中に存在し続け、実際Organismsとの違いがわからなくなってしまっていた面もありました。 その解消による開発体験の向上は大きかったです。 APIなどが内部で叩かれていたり、そのページでしか使われないロジックが入ってしまうならcomponents/[ページ名]の中に入れればよいと考えました。 逆に汎用的ならuiPartsに入れればいいというルールは他の開発者にもわかりやすいものだと思います。 規約の多くなりがちなAtomic Designを下手に採用するよりも自然に理解しやすいこの構成は、人の入れ替わりが多い現状の組織にもマッチしている気がします。 また以前、特定コンポーネントへの強依存によって思わぬ部分がバグってしまった経験がありました。 そのため大きいコンポーネントは各ページごとに管理できる本構成は、依存度を一定以下に保ちやすくて良いなと感じています。 この構造のデメリット まだ運用したての段階なので、これ!というデメリットは未だ見つけられてないですが、シンプルにcommitしたときのファイル数が増えます。 共通化という考え方からはかけ離れた結果なので、わかってはいましたが、プロジェクトの立ち上がり当初の、ButtonやTextFieldを作っているときの追加のファイル数が膨大になりがちでした。 最低でもindex,presenter,styledの3ファイルが増え、それに対してhooksを発行しようものならさらに増えるので、ビッグバンリリースになってしまう危険性やレビューで気が付ききれない可能性もあります。 しかし、この辺はPRを細かく出したり、リリースを細かくやったりと工夫のしようはかなりあるので、特性を理解しておけばあまり問題にはならないかなといった感じです。 今後の改善プラン 今回新構成を導入した後、フロントエンドに興味があるメンバーを集めて今後のフロントエンド改善をするための流れをまとめました。 今あとできる大規模な改善ではなく、すぐすぐできる細かい改善をメインでまとめましたが、以下のような問題が出てきました。 今後最優先でやらなくてはいけないことは以下のような感じです。 現状、BOXIL SaaS直下のディレクトリにはもともと存在していたfrontendという名前のVueディレクトリがあります。 そこで使われているeslintやpackage.jsonがfrontendディレクトリの中にはなく、ルート直下に置かれていました。 SaaS質問箱開発時だけではそれを直している時間がなかったため、いったん以下のようなディレクトリ構成で開発をしました。 BOXIL ├ frontend(Vue) ├ frontend_react(React) │ ├ package.json(React) │ ├ eslint(React) │ └ tsconfig(React) ├ package.json(Vue) ├ eslint(Vue) └ tsconfig ですが、このままだとfrontendとfrontend_reactの違いに迷う羽目になります。また、各種ディレクトリの中に入ってnpm installをするのもめんどうです。 それに対する今後の対応策を以下のように定めました。 チームメンバー内で話したメモをそのまま貼り付けているため、わかりにくくなってしまっているので図解します。 今後のディレクトリ構造を以下のようにしました。 BOXIL ├ frontend │ ├ react(React) │ │ ├ package.json(React) │ │ ├ eslint(React) │ │ └ tsconfig(React) │ └ deprecated_vue │   ├ package.json(Vue) │   ├ eslint(Vue) │   └ tsconfig └ package.json Vueのディレクトリが物騒な名前になってますが、これにはちゃんとした理由があります。 フロントエンドの一本化 今回Reactの導入により、フロントエンドの組み合わせは以下のようになりました。 Vue + TS Vanilla JS Coffee Coffee + Vue Coffee + jQuery React + TS お気づきでしょうか。Reactが導入されただけでは何1つ「改善」はされていません..。 むしろReactが増えたことにより、新しく開発チームに入った人はVue, Vanilla JS, Coffee, jQuery...とキャッチアップする領域が広がってしまいます。 そのため今後、BOXIL SaaS開発チームとしてフロントエンド技術の一本化をしたいと考えています。 Internet Explorerの終了に伴いこれまで開発改善の足を止めていたdecaffeinate-> ES5の記述に直す必要がなくなったことからまずはCoffeeがBOXIL SaaSのコード上から消えることになります。ありがとう、そしてさようならCoffee。 本来はここからVueのコンポーネントも含めてReactの一本化を目指すのがベターかと思いますが、工数的にそこまで大きな技術負債の改善ができるのはまだ先だと考えています。 明らかにレガシーになってしまった言語は負債ですが、Vueになっているものを優先度上げて対応する必要がないと考えたのも大きな理由の1つです。 そのため、Vueのディレクトリをdeprecatedとし、保守以外で新規ページの発行はせず基本今後SPAのページを作る場合はReactでの開発にまとめます。 そうすることにより、いったん以下のような構造になります。 Vue Vue + TS Vanilla JS jQuery React + TS あとはゆっくりjQueryを剥がせばすぐすぐの一本化とは行かずとも、ある程度採用技術がまとまってくるのではないかと考えています。 WorkSpaceの活用 現状各種ディレクトリに入りnpm installをしていますが、それだと各種ディレクトリにlockファイルができてしまったり単純に2回やるのがめんどくさいです。 WorkSpaceを使うことによりtopから各種パッケージを一元管理できるうえに、モノリポ構成としてもきれいなものになると考えています。 これをやるためには上記のディレクトリ改善をやったあと、CI / CDをいじるタイミングでまとめて新しい構造に変更するのが良いと考えています。 まとめ ...ということで、今回はBOXIL SaaSのフロントエンドに革命を起こすべくフロントエンド構成を立て直してみたという話をしました。 しかし、負債を作らないつもりで開発していても知らず知らずのうちに負債は出来上がっていきますし、「Vueを導入した方もCoffeeを導入した方も負債を作るつもりで導入したわけではない」ということを理解しておくのが大事だと私は考えています。 また、新しいものを導入しただけでは負債は改善されておらず、むしろ新しい技術が増えたことでより負債になる技術が増えたのが事実です。 これを避けるためには今後も定期的に技術負債の改善やアーキテクチャの見直しが必要で、個人的には特にSSRできていない今の状態が不服です。 しかし改善作業や技術の導入には自身の知識だけでは足りないものや、時間的に足りないといった事実も多々あると思います。 そのため今回は部署問わず知見のあるメンバーと積極的に話し合い、自分だけで決めずチームとして方針を決めて取り組むことを意識しました。 結果、別PJのメンバーがPRを上げてくれたり、アドバイスをくれたりと導入に協力してくれました。 とても感謝しています。 この記事が同じくレガシーフロントエンドの改善で悩んでいる組織の役に立てれば幸いです。
アバター
こんにちは。 今年4月より22卒エンジニアとして、スマートキャンプに入社したピーターこと佐々木です。 本記事では、入社エントリと題しまして、スマートキャンプへの入社理由と、実際に入社してみてどうだったかについて書きたいと思います。 自己紹介 なぜエンジニアになったのか エンジニアに興味を持ったきっかけ 原点は AI創薬とGoogleForm ひたすらに興味の幅をひろげる やりたいことなんてなくていい 私が大事にしていること 密な連携と高い生産性 密さとは 連携とは 生産性とは 広い視野をもつ 経験からしか学べない性格 〜なんでも自分でやりたい症候群だった〜 エンジニアの枠を超える イノベーションを起こせる環境 ものを生み出すのが好き 私が今エンジニアである理由 なぜスマートキャンプに入ったのか? 出会ったきっかけ 決め手は求める環境が揃っていたこと 1. 個人を称賛する文化 密な連携と個人称賛 メリハリをもって働ける環境 まとめ 〜キャンプのような会社〜 2. 視野を広げ自分の可能性に気付ける 多くのビジネスとの接点 担当できる技術領域の広さ 3. 挑戦し続けられる環境 挑戦しやすい環境 さらなる挑戦の連続 まとめ 実際入社してどうか? マネーフォワードとの合同研修 予想以上に得るものが多かった研修 配属されて これからも学びや活動を発信していきます! 自己紹介 軽く自己紹介します。 【基本プロフィール】 - 埼玉県出身 - 6年制薬学部卒 - ルービックキューブが好き なぜエンジニアになったのか 一言でいうと、ものを生み出すことで、ユーザーに 新しい価値 を提供できることに魅力を感じたからです。 そのため、与えられた選択肢の中から選び、そしてその妥当性の評価が主である薬剤師の仕事は、とても重要だとは思いつつも私の性には合わないと感じました。 また、試行錯誤しながらプログラムを書くことができるエンジニアに対し、人の命を預かりミスが許されない薬剤師は、経験から学ぶ私には向いていなかったとも思います。 詳しく見ていきます。 エンジニアに興味を持ったきっかけ 原点は AI創薬とGoogleForm 私は6年制薬学部に在籍していました。 別段、薬剤師という仕事に魅力を感じてはいませんでしたが、医療と人体の仕組みには興味があったのと、卒業し国家資格をとれば職には困らないだろうと考え、自分がほんとにやりたいことをこの6年間で探そうというスタンスで大学生活を送っていました。 例えば、長期休みには海外留学にいったり、既存のサークルに入るだけでは飽き足らず、当時ハマっていたルービックキューブをやるサークルを立ち上げて、大学対抗の大会に出場したりしたこともありました。 そんな中、プログラミングに出会ったのです。 きっかけはよくあるプログラミング教室からの勧誘でした。 当時私は2つの理由から、その誘いに乗ったことを覚えています。 1つは、AI創薬への興味です。 大学の講義で、「※難病や稀な病気の患者に対する薬は採算が合わないので企業は開発しない」という話を聞きました。その話を聞いたときに、私はそういう人の味方でありたいと憤り、当時話題になりだしていた AIをはじめとした新しい技術を使えば、その課題が解決できるのではないかと仮説を立て、AIについて詳しく勉強してみたいと思っていました。 ※ 実際は国から補助金がでたり、優先的に審査されたり、特許期間が延長されたりするので、全く開発されないことはないです。 もう1つは、当時(2017)初めて使ったGoogle FormとLINE@の機能に感動したことです。 「〇〇検定」のような、問題を作って採点できるアプリをGoogle Formで簡単に作れることを知り、試験の予想問題集アプリとして勉強に役立てていました。それをサークル内で共有したところ、回り回って学年のほぼ全員が使ってくれたのが、グラフと共に確認できて、めちゃくちゃ興奮したのを覚えています。LINE@はサークル勧誘に使いました。「LINE登録すると、ルービックキューブが無料で受け取れるクーポンがもらえる」とサークル勧誘のビラに QRコードを載せたところ、反響を生んで、多くの新入生に対して説明会の通知を一斉に送ることができました。 このような経験から、もし自分でコードを書くことができたら、もっと面白いことができるのではないか?という期待を持ちました。 そして、すぐにコードを書く楽しさに虜になり、ドハマリしていたルービックキューブそっちのけで、ひたすら自分の考えを形にする面白さに酔いしれていきました。 ひたすらに興味の幅をひろげる その後就活に至るまで、私はAI・機械学習、Web開発、モバイルアプリ開発、ゲーム開発、競技プログラミング、バイオインフォマティクス、ケモインフォマティクスと、螺旋階段を登っていくように、なんども挫折と再挑戦を繰り返しながら、徐々にプログラムを書くことによってできることの幅を広げていきました。 大学5年生になる頃、ちょうど例の感染症が流行り始めたと同時に、薬局実習、病院実習が始まりました。そして、その中で、私は就活のことを考え始めました。 やりたいことなんてなくていい 進路はとても悩みました。 「色々なことをやってきたけれども、結局自分はそこから何を学び、これから何をしていきたいのか。」 この答えはなかなか得られませんでした。 しかし、そんな中、ある1冊の本に出会い気づきました。「やりたいことは後から見つければいい。」と。 その本の中では、大事なこと(Why)を第一に見つめ直しそれが満たせる環境で、自分の得意な方法(How)で、好きなこと(What)ができるようにすれば、それがやりたいことになると紹介されていました。 逆に言えば、どんなにテクノロジーが好きでも、居心地の悪い環境で、苦手な方法で仕事をしていたらやりたいこととはズレてしまっているということです。 私は、テクノロジー好きが高じて、新しい技術を開発するベンチャー企業でインターンをしたり、研究室でAIを使った創薬研究をしたりしていましたが、切磋琢磨できるメンバーのいない環境で、人に言われたことを淡々とやるような状況になったとき、しんどい気持ちになってしまった経験があったので、この話はとても腑に落ちるものでした。 そのため、何をしたいかではなく、 自分にとって何が大事か 、自分にはどういう価値観があるかを見つめ直しました。そして次に、自分の得意なことを活かすことを考え、最後にそれで結局自分は何をやりたいのかを考えようと決めたのです。 私が大事にしていること 自分にとって大事な価値観を集約すると、以下のような環境が私には必要なことが見えてきました。 チームメンバーと 密に連携 が取れ、 高い生産性 を維持できること。 広い視野が持てること 。エンジニアとして広い技術領域が必要とされ、かつビジネス視点も身につけられること。 新しい技術 、ビジネスモデル、ノウハウ、人を 貪欲 に取り込もうとする文化があり 挑戦し続け られること。 その理由を、ここでは具体的な価値観とともに紹介していきます。 密な連携と高い生産性 私は、常に生産的であろうとし、そして、それを周囲の人にも求めてしまう性格です。 密さとは "密さ"とは、私の中で「苦楽をともにして刺激し合うこと」です。 私は、喜びは誰かとシェアしないと、素直に喜べない性格です。 それはおそらく、幼少期から「美味しいものはみんなで食べるから美味しいんだよ」という母の言葉に共感していたからだと思っています。 人と苦楽をともにし刺激し合うことで、お互いにモチベーションが駆り立てられ、精力的に仕事に取り組めると思っています。 反対に形式的な職場ではうまく働けません。どこまで何をすればいいのか、すり合わせるのに苦労します。 このように、仲間意識が強く味方がいると力が湧いてくる性格です。 試験勉強が辛いとき、いつも「友人のあいつも頑張ってるだろうから自分もやらねば」と奮い立たせていました。 連携とは "連携"とは、私の中で「得意を活かし、弱点を補完しあうこと」です。 私は、完璧な人間など存在しないと思っています。 よく人という字は、「二人の人が支え合っている姿を模したもの」だという話を聞きますが、まさしくこのイメージです。 そのため、誰もが自分が役に立っていると実感できるチームにこそ、個々人の高い生産性が望めると思っており、そのような環境下で仕事をしたいと考えています。 幼少期は、なんでも1人でできると思っていましたが、高校を卒業する頃には、誰かを頼る重要性に気づき始めていました。 コラム: 2割の怠ける働きアリとして生きていく 私は、人と違うことに積極的です。 誰かとランチにいく時、基本的に同じものは頼みません。 人と違うことで、自分には個性がある。そう思っていました。 そんな私が、アイデンティティーを失ったことがありました。 当時は意図して気づかないふりをしていましたが、私は高校に入学したときに、強烈に個性を失った気がしていました。 それは勉強しかしてこなかった私が、自分よりもできるやつらに囲まれた環境下に身をおいたからです。自分の存在意義、自分の餅はどこにあるのだろうかと。 そして、逃げました。勉強から。 まさに2割の怠ける働きアリの姿そのものでした。 そんな中でも、周囲から評価されることが1つありました。それが工芸です。 工芸とは、主に木工で家具などを作る科目でした。元来ものづくりが好きで、小学校・中学校の工作である程度評価されることが多かった私は、工芸との親和性が高かったんだと思います。 そのため、工芸だけはいつも成績がよく、その授業だけは唯一負けたくないと思えるものでした。 このような思春期の強烈なアイデンティティーの喪失と、新たなアイデンティティーの確立経験は、のちの私の価値観に影響を与えました。 チームの中で、全体像をみて、自分が補完できるところをついつい探してしまう性格の原点はここにあると思います。(実際、2割の普段怠ける働きアリは、働き者のアリが動けないところを穴埋めするようです。) 生産性とは 生産的であること。これは私にとって最も重要です。 1日の中で何もしていない時間があると、それだけで今日は虚無な1日だった、とネガティブな気持ちになりがちです。 幼少期、毎日のように習い事に行っていた結果、逆に予定がないことに不安を覚えるようになってしまったのかも知れません。子供の頃は、落ち着きがなかったので、よくずっと泳いでないと死んでしまうマグロのようだと言われていました。 休息を適度にとりながら、集中して没頭できる時間を大事にしたいと思っています。 広い視野をもつ 私は、広い視野をもつことで、自分の存在価値が認識できると思っています。 経験からしか学べない性格 〜なんでも自分でやりたい症候群だった〜 教育熱心な母のお陰で数々の成功体験を幼少期に得たおかげか、なんでも自分でやりたいと思っています。 分からないことは調べるというより、とりあえずやりながら考える。それがお決まりのパターンです。 それがプログラミングとは合っていました。とりあえずコードを書いて実行すれば、何度ミスしても毎回丁寧にエラーを出して教えてくれます。人の命を預かる仕事では、そうはいかなかったと思います。 そのため広く技術に触れられる環境を欲していました。 エンジニアの枠を超える エンジニアの枠にとらわれず広い視点を持つことで、自分たちが作るプロダクトがどのような価値を提供できて、どのくらい採算が立つのか、自分の作った機能がどれだけ売上に貢献できたのかが分かるようになりたいと思っています。 自分にとって、自分がやっていることの意義を意識するのは当然のことです。 人生に意味のないことはないと思いますが、経験上、意義を意識しないと時間が無駄になると学んだので意義を常に意識しています。 そのため、職種にとらわれず、誰が何をしているかを自分自身が理解できる規模・環境を望んでいました。 連携の項でも触れましたが、それは組織の中で 自分が最も貢献できるポイントはどこか を理解するためです。それが自分が存在する意味に繋がります。 「 コードに集中するために、ビジネス的なところはスッキリさせておきたい 」という気持ちが私の中には常に存在しています。 イノベーションを起こせる環境 私は、何も考えず、未知に飛び込める性格です。 ものを生み出すのが好き 私は昔から、純粋に新しいものを生み出すのが好きでした。 思い返せば、バレンタインはいつも手作りを渡す側。あるときは、そのケーキを焼く鍋すらも、銅板から自作したこともありました。 そのため、与えられた選択肢の中から選び、その妥当性の評価が主である薬剤師の仕事は、とても重要だとは思いつつも私の性には合わないと感じました。 それよりも、ものを生み出すことが楽しい気持ちを大事にしたいと思ったからです。 そして、特にテクノロジーに着目しました。先のエンジニアに興味をもったきっかけで話したように、そのできることの幅と可能性の広さにわくわくする気持ちを抱いたからです。 そしてイノベーションは、挑戦なくして生まれないと思っています。新しいものへのアンテナが高く、貪欲に取り組んでいく姿勢や、新しいものを自分から取り込める 挑戦しやすい環境 を望んでいました。 面白いと思えることに敏感になって飛び込んでゆける若さをいつまでも持っていたいと思います。 私が今エンジニアである理由 実は、エンジニアという職自体に対する強いこだわりはありません。 自分にあった環境で、自分の得意な方法で、好きなことができればそれでいいと思っています。 エンジニアは私にとって手段の1つであり、革新的なサービスの開発に取り組み続ける中で見えてくるいくつもの道のいずれかを辿って、人類の進化の果てを見届けたいと願っています。 なぜスマートキャンプに入ったのか? 一言でいうと、先述の私の求める環境が揃っていると確信したからです。 特に、スマートキャンプの VISION「 Small Company, Big Business. 」には、少人数チームでも社会を動かせることを証明するという強い意志を感じ、気に入りました。 この少数精鋭による高い生産性を追究する姿勢が、自分の求める環境と一致していると思い入社しました。 出会ったきっかけ 自分の求める環境像は定まったものの、正直企業のHPをみても会社の雰囲気は全然わかりません。普通ならOB・OG訪問などアポを取り付けて話を聞きにいくのかもしれませんが、大半が病院や薬局、ドラッグストアに就職する大学の特性も相まって、それは考えませんでした。そして、逆にエンジニア専門のエージェントに会社を紹介してもらう手段をとっていました。 最初に10社ぐらいの候補から、数社ピックアップすると、それに沿って他の企業を推薦してくれたり、予め登録したエントリーシートを提出してくれたりします。感触のよい企業だと、すぐにコーディング試験や面接のお誘いがくるのでそれに従い受けていました。 その中で、スマートキャンプに出会いました。 事前に受けたコーディング試験の結果を基に、技術的な部分を深ぼられるのが最初の面接でした。その面接で「ちゃんと自分の技術面を評価してくれる企業だな」と感じ、かなり印象が良かったのを覚えています。 良くも悪くも事業自体にあまり興味がなく、 価値観や得意なことを重要視 していたからこそ、スマートキャンプに巡り会えたと思っています。 今振り返っても、私は、就活時点ではやりたいこととかなくていいと思っていますし、それよりも自分がどのような環境だったら、無理なく仕事できるかとか、強みを発揮できるかを見つめ直すことのほうがよっぽど大事だと感じています。 決め手は求める環境が揃っていたこと ここで、一度私が求める3つの環境をおさらいしておきます。 チームメンバーと 密に連携 が取れ、 高い生産性 を維持できること。 広い視野が持てること 。エンジニアとして広い技術領域が必要とされ、かつビジネス視点も身につけられること。 新しい技術 、ビジネスモデル、ノウハウ、人を 貪欲 に取り込もうとする文化があり 挑戦し続け られること。 スマートキャンプには、1. 個人を称賛する文化があり、2. 視野を広げ自分の可能性に気づける上に、3. 挑戦し続けられる環境があり、自分が求める上記の環境が揃っていると確信したため入社しました。 1. 個人を称賛する文化 スマートキャンプには、 個人を尊重 する文化と、 集中 して 業務 に取り組める環境があります。 密な連携と個人称賛 エンジニア組織は、プロダクトに横断的に関わることができる独立した組織になっていて、自分が担当しているプロダクト以外の進捗も毎週確認できます。選考過程で見学した際に、デザイナーや営業の方の意見も踏まえて議論が進んでいく様を見て、それぞれのメンバーが強みを発揮できる場が揃っているのだなと感じました。 それだけでなく、基本的にDMが禁止なオープンコミュニケーション文化のため、他の人が何をやっているかが見えやすいです。 またピアボーナス制度を導入しており、社員同士で称賛し合う文化が根づいている点も素敵だなと思いました。 そして特筆すべきはSMARTCAMP AWARDです。 SMARTCAMP AWARDでは、社員一人ひとりが自分が成し遂げたことを発表する場です。 お互い称賛し合うと共に、 職種を超えて誰がどのようなことをしたのかが分かりやすい 環境が整っています。 メリハリをもって働ける環境 スマートキャンプでは、スクラム形式で開発を進めており、毎週金曜日にその週の進捗確認と次週やるべきことの棚卸しを行います。私はハッカソンのような短期集中して開発するイベントが大好きなので、このような環境なら集中して開発に臨めそうだと思いました。 まとめ 〜キャンプのような会社〜 このように、個人を尊重し強みを生かして連携し合うような土壌と、集中して開発に望める環境が揃っており、密な連携と高い生産性が維持できると考えました。 そもそもスマートキャンプの"キャンプ"には、 多種多様な人が同じ目標に向かって進む という思いが込められており、それもまたいいなと思いました。 そのような風通しの良さが気に入りました。 2. 視野を広げ自分の可能性に気付ける スマートキャンプには、 技術的 に関わることができる 領域が広く 、さらにSaaS業界レポートなど ビジネス に対する アンテナが高く 世のトレンドもつかみやすい環境があります。 多くのビジネスとの接点 スマートキャンプのBOXIL SaaSというプロダクトは、サービスを売りたい企業と導入したい企業のマッチング的なビジネスモデルになっています。また、"SaaS業界レポート"というSasS業界の動向をおさえた資料を作成しています。このように 多くの会社の様々なプロダクトに触れる機会 がありビジネス視点も学びやすいのではないかと考えました。 また、評価制度上、エンジニアといえど組織貢献度が重視され、広い視野が求められるところが自分の目指すエンジニア像と重なりました。 担当できる技術領域の広さ スマートキャンプは創業から少し経っていて、ある程度サービスの規模も大きくなってきました。とはいえ、サービスごとの開発メンバーは多くても5〜6人規模と少人数でそれぞれのメンバーに広い技術領域が求められます。 このような環境は私の望むものでした。 自分の理解できる領域が多ければ多いほど、どこに力を入れたらサービスに大きなインパクトを与えられるか考えやすいですし、自分ごととして捉えられると思ったからです。 さらに、これからもいくつも新しいサービスを開発していくはずであり、自分が 挑戦できる範囲が広い だろうと睨んでいます。 3. 挑戦し続けられる環境 スマートキャンプには、 挑戦しやすい環境 が整っているだけでなく、さらなるシナジーによる イノベーション創出機会 が多々あります。 挑戦しやすい環境 私は、常に進化を続けていくためには、新しいものに対する貪欲さが必要だと思っています。 スマートキャンプは「 テクノロジーで社会の非効率を無くす 」とミッションを掲げています。ここから、新しい技術を積極的に取り入れていく姿勢だったり、今現在提供しているサービス内容にも全然満足しておらず、もっと劇的な非効率解消をやるぞという意気込みを感じました。 このようにテクノロジーを取り込む姿勢は、言葉だけではありません。 また、AWARDで表彰された新卒社員がいること、新卒社員から「やりたいことを実際にやらせてもらっている」と聞いたことから、 挑戦しやすい土壌 ができていると考えました。そして私が挑戦したい新規事業の立ち上げも実現できるのではないかと思いました。 さらなる挑戦の連続 私は、さらなる挑戦、イノベーションには外部との協力が不可欠だと思っています。 スマートキャンプは、日本では事例の少ないスタートアップのM&Aという挑戦を成功させ、シナジーを創出し続けています。 2人の人間同士が理解し合うのですら困難なのですから、全く異なる文化を持った会社が1つになり事業を進めていくのは、全く容易ではないことだと思います。 それを成功させ、シナジーを生んでいる企業であるならば、これからも様々なシナジーを創出し、挑戦の機会が生まれるだろうと考えました。 結局のところ、自らの立場を主張しつつも、他のところと共生できること、共創できることは強みだと思います。 まとめ ここまで長文に目を通していただき、ありがとうございます。 このように、スマートキャンプには、 個人を称賛 する文化があり、 視野を広げ 自分の可能性に気付けて、そして 挑戦し続け られる環境が揃っていて、私の求める環境だったので入社を決意しました。 そして、実際に入社してそのギャップはどうなのかに入ります。 実際入社してどうか? 簡単に入社してから現在までの流れはこのようになっています。 入社(2022.4.1 ) 全体研修(2022.4.4~4.22) エンジニア研修(2022.4.25~5.31) 座学・ハンズオン CS(Costomer Support) データマネジメント・分析 機械学習 UX 設計 AWS サーバーサイド フロントエンド QA(Quality Assurance) 実践 PBL(Problem-based Learning)研修 部署配属(2022.6.1~) EVENT カンパニーに配属 マネーフォワードとの合同研修 最初の2ヶ月は研修でした。 前半は、マネーフォワードグループの新卒全員との合同研修で主に社会人としての心得などのマインドセットをメインに学びました。 後半はエンジニア研修で、CS(Customer Support)研修から始まりました。「エンジニアなのに、Customer Support?」と思いましたが、行動指針にUser Focusを掲げるマネーフォワードらしい構成だなと感じました。 予想以上に得るものが多かった研修 前述の通り、仕事には少数精鋭で取り組みたかったので、同期の人数をそこまで重要視していませんでした。しかし、結果的にはマネーフォワードの多くの同期と研修が受けられて本当に感謝しています。 エンジニアとは程遠い領域で大学生活を過ごしていたこともあり、同期とテクノロジーの話ができる事自体が非常に新鮮でした。 特に一人では勉強しづらいインフラ周りを、チーム開発でたくさん触れることができたのはとても大きかったです。少し自信も付きました。 それと同時に、チームで開発する難しさも感じ悔しい思いをするとともに、業務にも役立てられる学びも得ることができました。 配属されて 私は、BOXIL EVENT CLOUDというBOXIL EXPOのオンライン配信を行うプラットフォームの開発を任される部署に配属されました。 任されたプロダクトは、仕様検討、アーキテクチャ設計、技術選定とほぼ開発初期段階から関われるもので、選考時の要望と合致していました。 この恵まれた環境を活かすも殺すも自分次第。頑張っていきたいと張り切っています。 これからも学びや活動を発信していきます! ここまで、長文を読んでいただき感謝感激雨あられです。 業務を行う中で得た学びや活動を発信していきますので、今後もよろしくお願いします!!
アバター
braavaです はじめまして!! 2022年の4月より新卒として入社した藤原です!! 社内ではブラーバと呼ばれています。 大学時代は情報系の大学に通いながらブラウザゲームの開発アルバイトなどをしていました。 就活~入社の流れ 最初に就活から新卒として入社するまでの流れをざっくりと書きます!! エンジニアアルバイト時代(2020/01~) 大学2年生の冬から京都でブラウザゲームの開発に携わる 利用していた言語はPHP 就活 ゲーム事業をしている企業の選考にたくさん応募 SaaSがやりたいと考えを改め、就活を再度やり直す スマートキャンプの選考に応募し、内定を貰う 内定者インターン(2021/09~) オンボーディング BOXIL SaaSの機能開発 新卒入社(2022/04~) 全体研修 エンジニア研修 BOXIL SaaSに配属<-now!! 次にスマートキャンプに入社を決めた理由を書きます!! 入社理由 大学2年生の冬からブラウザゲームを開発するアルバイトをしていました。そのときに同じオフィスにいた営業の方々がBOXIL SaaSを利用して案件を獲得しており、そこでBOXIL SaaSというプロダクトを知りました。 そして調べていく中でそのビジネスモデルに非常に興味を持ったため選考に応募しました。前述の通りそれまではゲーム業界の選考ばかり受けていましたが、BtoBのSaaSに興味が生まれ選考を受けていく過程でスマートキャンプの言いたいことがしっかりと発言でき、業務改善をしようという空気が好きになりました。内定を頂いてすぐに内定承諾をしたことを覚えています。笑 2021年9月から内定者インターンを行ないましたが選考時に感じた空気感は変わらず、気持ちよくエンジニアの業務ができる環境だなと感じています。 内定者インターン ここでは内定者インターン時の業務内容を書きます!! 主に行なったのはオンボーディングと研修、そして機能開発です。 オンボーディング まだ経験も浅かったので、研修としてBOXIL SaaSと同様のアーキテクチャで簡単なWebサービスを作りました。 練習用でとても大味なものでしたが、BOXIL SaaSで利用している技術を知るにはすごく良かったです。このおかげで業務に入る際にストレスなく開発を始めることができました。 機能開発 また年末からBOXIL SaaS上で発生する資料請求の通知をSlackに送るという新機能の開発を任されました。 それまではメールでの通知のみですがSlackで通知が来るとより早く資料請求を活かせるという要望から企画された機能です。 調査から設計、実装と社員さんのお力を借りながらですがすべて自力で行なえたので非常に良い経験でした。 この通知はBOXIL SaaSの肝である資料請求から発生するもので、資料請求のドメイン知識も開発には必要とされるためそのキャッチアップが少し困難でした。 また資料請求発生から架電までの時間が短いほど案件獲得の確率は上がるため、通知のエラーハンドリングにも注力し開発しました。 週2~3という不定期で少ない業務時間の中なんとか内部リリースまでを新卒入社の前に終わらせることができました。 研修について 2022年4月からは株式会社マネーフォワードの新卒と一緒に新卒研修を2ヶ月間行なっていました。 ここからはその内容を簡単に書きます!! 全体研修 最初の3週間は全体研修でビジネスマナーやロジカルな思考を手に入れるための研修を受けました。ただ受け身の座学ではなくinputの時間とoutputの時間がそれぞれの研修で散りばめられており、社会人としての心得や思考などが少しは身についたかなと思います。 またスマートキャンプの行動指針を体現された方にインタビューをし、その内容を全社に向けて発表する取り組みも行ないました。 同期と一緒にインタビューの設計をし、そのインタビューから自分たちなりの言葉でプレゼン資料を作っていくことでよりSOCSというものを自分ごとに考えられたかなと思います。 エンジニア研修 そして4月下旬からはエンジニア研修でした。GWをはさみつつ最初の2週間は座学でエンジニアリングに必要なものを学びました。印象に残っている研修はUX設計とAWS、サーバーサイドの研修です。 UX設計は実際にユーザーインタビューをし、ターゲットを絞りつつ課題を見つけるという研修で後述のPBL研修で非常に役に立ちました。これは配属後にも非常に有益な研修だったと思います。 AWSの研修ではECSやLambdaなどを実際にマネジメントコンソールから立てたり、講師の方が出した課題を同期とわいわい言いながら解いていきました。 そしてサーバーサイドの研修ですが、利用したプログラミング言語はGo言語でした。出された課題の難易度がstepを追うごとに上がるというもので、一人でもくもくと時間制限いっぱいまで作業していたため少し疲れましたが、課題を達成できたときは嬉しかったです。 PBL(Project Based Learning)研修 課題の内容は 新社会人のお金の課題を解決する と 動くものを2週間で作る というもので、4人ずつのチームで取り組みました。 新社会人のペインを見つけ出すことは少し難しかったですが2週間で作りたいサービスをしっかりと作ることができたので非常に良い研修だったと振り返りながら感じます。 私達のチームは「聞きづらい相手の収入を知らずとも家賃や生活費などの負担額をフェアに計算してくれる」というニッチなサービスを作りました。 これは同じチームにパートナーと同棲をしているメンバーが2人いたこともあり、新社会人の同棲に何らかのペインがあると仮設を立て、インタビューをしていく中で固まったサービスでした。理想のサービスから2週間でやりきれる機能を取捨選択しつつ最後にはUserFocus賞というユーザーのことを考えたサービスに贈られる賞をいただきました。 サービス画面 マネーフォワードの同期は優秀な人が多くとても刺激を受けましたし、そのなかで自分がどのような役割だとチームに貢献できるのかということを学ぶことができました。 今後の抱負 もともとクラウドインフラへの興味があったり、サーバーサイドをずっと触っていたり、フロントの技術に興味があったりとなんでも触りたい時期ではあるんですがプロダクトとしてはBOXIL SaaSの開発に携わることは決まっています。BOXIL SaaSのインフラやサーバーサイド、フロントを支えつつ、スマートキャンプをより良い組織にしていきたいと思っております。 テクノロジーでぶん殴るぞ!!
アバター
スマートキャンプでエンジニアをやっております永井です。 若葉の緑が目にしみる季節となりましたが、皆さまいかがお過ごしでしょうか。 この度4/20にSaaS特化型Q&Aサイト「 BOXIL SaaS質問箱 」のβ版を公開しました。 prtimes.jp SaaSの選定をはじめ、そもそも何をすれば良いか分からずお困りの方はご質問の投稿お待ちしております。 いきなり宣伝からはじめてしまいましたが、今回はこのプロダクトの開発で色々試したことがあるので、それを「開発前編」と「開発中編」に分けてご紹介します。 私は今回のPJではPMと開発を半々でやっていました。ちなみにPMっぽいことははじめての経験です。 開発前編 初期 問題点 やったこと グロースサイクル図の作成 OOUI 開発編 朝会 タスク管理 見積もり ブランチ戦略 結果 振り返り 開発前編 初期 開発初期段階の状態はこのような状態でした。 開発陣(エンジニア, デザイナー)が参画時は要件がある程度決まった状態 POが作成したワイヤーフレームは作成済み 納期はざっくりと指定(2ヶ月位) まずMVP(Minimum Viable Product)を出すため後回しにする機能を見極める必要がある 問題点 問題としてまず上がったのが、「このPJでやりたいことの背景を開発陣が知らなさすぎる」というものでした。 当初MVPをまず作るべく、削れそうな部分を話し合っていましたが削って良いところかの判断がつきません。ワイヤーフレームというUIベースでのお話がメインとなっていたので、ミクロ視点での話になることも多く、「なんでこれやってんだっけ」という状態になることもしばしばありました。 すでに見た目の草案も出来上がっているため、デザイン作業を進めるときにもワイヤーフレームに引っ張られ、デザイナーがデザイナーとしての本領発揮ができないことも考えられました。 やったこと このままではかなり受け身な状態で開発が進み、成果物がぶれ手戻りや修正などにより納期に間に合わない可能性がありました。 そこでメンバーと相談の末このサービスはどういったもので、どうやって大きくなっていくか、またそのために必要な要素は何かをあらためて開発に携わる人全員で話すことにしました。 その時実施したのが「グロースサイクル図の作成」と「OOUIの図の作成」です。 グロースサイクル図の作成 グロースサイクルとはプロダクトの成長を定義した循環モデルのことです。 詳しくは以下記事を参照してください。 applis.io 解説のために(大分)簡略化したサンプルを用意しました。 グロースサイクル図サンプル 色々端折っていますが、質問が増える→回答が増える→見る人が増える→質問が増える→……という事を繰り返してサービスを大きくしていこうね、という考えを図示したものです。いわばこのサイクルがサービスの芯の部分となります。 これを皆で話しながら作ることで、その後のMVPの策定や優先順位付けがとても楽になりました。上の図でいうと「これは質問が増える施策からは離れてるので、MVPからは外しても良さそうですよね」みたいな話ができます。 OOUI OOUIとはざっくり言うとオブジェクト(もの、名詞)を中心にUIを設計する考え方です。 詳しくは弊社デザイナーの柿澤の記事を参照ください。 note.com サービスの要素をオブジェクトで分解することはエンジニアがクラス図を考えるときと似ているため、デザインをエンジニアも含めて皆で考えるという新鮮なことができました。 サンプルとして、BOXIL SaaS質問箱におけるモデルの一部をお見せしますが、オブジェクト・プロパティ・アクションとほぼクラス図のような定義だと伝わるかと思います。 OOUIの設計イメージ その後のUIデザイン自体はデザイナーにお任せしましたが、どういう要素があってどのような背景からこの遷移になったのか、という事が共通認識として得られたのでその後の開発に良い影響を与えたと思います。 あとは純粋にパズルみたいで楽しいです。今回ご紹介したBOXIL SaaS質問箱の場合、「質問への回答はどういう遷移、見せ方が良いか」みたいな話ができるのは新鮮でした。 開発編 開発は基本的にはスクラム開発をベースに進めました。エンジニアは私ともう二人(フロント, サーバー1名ずつ)の計三名です。 色々試したことを列挙するので、参考になれば幸いです。 朝会 週3で30分程開発陣以外も含めたチーム全体でのオンライン朝会を開きました。 主に進捗報告と仕様の相談が目的でしたが、初対面のメンバーもいてなおかつテレワークだったため良い交流の場としても機能していたように思います。 タスク管理 タスク管理はAsanaを使い、ストーリーベースで管理しました。「○○のAPIを作る」より「ユーザーが質問投稿できる」というチケットの方がメンバーに共有しやすく、POへの共有・確認もしやすいと考えたためです。 Asanaのタスクイメージ ユーザーストーリーについては以下の記事で詳しく解説しています。 ssaits.jp 朝会で口頭のみで話したことは極力チケットに残すようにし、漏れないように務めました。「とりあえずAsanaを見ておけばOK」という状態に近づけました。 見積もり 見積もりはTシャツのサイズ(S,M,L)を使用しました。これは数値での厳密な見積もりより素早く共通認識を取るためです。結成したてのチームで見積もりの精度も未知数だったため、まずはざっくりと見積もることで勝手を知る狙いもありました。 ざっくりと付けられる割には、想定したサイズがメンバー感で異なることで話が進展したりと想定以上に機能したように思います。 Tシャツ見積もりについては以下を参照ください。 asana.com ブランチ戦略 今回の開発環境は1つのレポジトリで管理されている環境(モノレポ)に追加で作る要領で開発を進めました。 モノレポ環境に大きな機能(あるいは新ページ)を開発する際によくあるのが「超特大ブランチ出現問題」だと思います。経験上コンフリクトの解決などの手間が増えあまり良い開発体験にならないと思ったので、できた機能からリリースブランチにマージ後にリリースする方針にしました。権限で分岐し、一般公開はしないようにしてこれを実現しました。 詳しくはこちらの記事で解説されています。 developer.hatenastaff.com このおかげでリリース日も最後の非公開の設定を外した小さなPRをマージしてデプロイするだけで済んだので、リリース作業中に祈る時間も最小限に抑え、余裕をもってリリースできたと思います。(多少は祈った) 結果 結果としては無事にリリースができましたし、背景からサービスを理解することで自分ごととして捉えやすく、モチベも高く作業に当たることができました。作っている中でアイデアも湧くこともあったので、今後も改修していく所存です。 振り返り 振り返ってみると、プロダクト開発においては一発逆転ホームランのような手は無い、ということを体験したように思います。 開発者が俯瞰することや、情報をしっかり管理すること、密なコミュニケーションなど地味だけど良さそうなことを地道にやった結果、開発がある程度上手く回ったのかなと感じました。 紹介しておいてなんですが、OOUIやグロースサイクル図, Asanaなどはあくまでもツールで、大事なのはその辺りの目的を見失わないことなのかなと思っています。 スクラム開発も上手く回すこと自体が目的になってしまうこともしばしばあったので、以後気をつけたいと思いました。 また不具合修正が少し押したり、属人化を回避しきれなかったりと課題も少なからずあるので、これらの経験も活かして地道に改善していきたいなと思ってます。
アバター
こんにちは!スマートキャンプ社でエンジニアとして働いている井上です。 この度開発改善でBALES CLOUDのバックエンド環境をRails 7・Ruby 3へのアップデートを1日でやりました!※リリースは調整などもあったので別日にやっています。 Rails・Rubyアップデートの具体的なコマンドなどはすでに書かれている記事などが多いので 今回は、1日でアップデートできた理由とどんな手順で進めたかなどを紹介できればと思います。 1日でアップデートできた理由 いきなり1日でアップデートできた理由を話をしますが、今回のアップグレード作業はマンパワーで一気にやったわけではなく1人でアップデート作業をしました。 これが可能だったのは自動テストの充実度と依存するgemが少なかったことによるところが大きいと思います。 自動テストの充実度 Rails・Rubyアップデートも機能のリリースと同様にRSpecやその他のテストでリリースのリスクを小さくしリリースするという点は変わらないと思います。 BALES CLOUDはRSpecのカバレッジは90%ほどあり、mablによるE2Eテストでもテストをしており 重要な機能の基本動作はテストは自動テストで担保できる状態にありました。 そのため、これらのテストが通れば問題が起こる可能性はある程度少ないといえる状態でした。 また、当たり前かもですがリリース後に問題があればすぐに戻すという前提でリリースしました。 幸い、戻すようなことはなくパフォーマンスも安定しバグもない状態でリリースが完了しました。 https://tech.smartcamp.co.jp/entry/introduced-mabl mablについては こちら の記事を読んでいただければと思います! 依存するgemの少なさ 依存するgemが少ないとアップデートの手間も少なくなります。 仮にメンテナンスがされず、Ruby 3やRails 7をサポートしていないgemがある場合、代替を探すという作業が発生します。 今回はすべてのgemをアップデートするのみで大きな修正がなかっためアップデートも楽でした。 ※ gemを使わないようにしようという話ではないです。 実際にやった作業 実際にやった作業を紹介していきます。 Railsアップグレードガイド && RubyのRelease記事を読む Ruby・Railsをアップデートする Rails sで起動できるようにする RSpecを通す mabl(E2EテストSaaS)のテストを通す stg環境リリース && 動作検証 Railsアップグレードガイド && RubyのRelease記事を読む 主にここで確認したのは変更と削除のあった箇所です。 観点としてはアップデートした際にどの程度の修正がありそうかだったり、暗黙のうちに変更されて障害が起こる可能性がある箇所がないかを確認しました 幸い、あまり対応が必要な箇所がなかったので割と楽にアップデートができました。 実際に読んだものは下記のものです、アップデートの注意点だけでなく今後使えそうな機能の学習もできました。 とても助かりました! https://www.ruby-lang.org/ja/news/2020/12/25/ruby-3-0-0-released/ https://github.com/ruby/ruby/blob/v3_0_0/NEWS.md https://railsguides.jp/upgrading_ruby_on_rails.html Ruby・Railsをアップデートする 実際はそれぞれ個別にアップデートを行っていました 一気にやると問題がどこにあるかわからなくなったり、どのアップデートによる問題なのかの切り分けが難しくなるからです。 例えば、今回だとRubyのアップグレードでキーワード引数周りの仕様変更がありました。 それに伴い関連の箇所でエラーが大量に出ましたが、これもRuby関連の対応とRails関連の対応とを同時に行なうと問題はわかりにくくなるので 個別でアップデートして検証していくことをおすすめします。 Rails sで起動できるようにする gemのアップデートをしても大体起動しないことが多いかと思います。 今回も特定のgemのoptionが削除されていたことが原因で最初は起動しませんでした。 この辺は個別にgemの変更やアップグレードガイドなどを読み変更漏れがないかなどをログを元に1つ1つ確認していく作業でした。 RSpecを通す 主にキーワード引数周りでテストが落ちていたので修正しました。 多くは、引数の委譲がよく使われており、そのエラーが大量にでましたが 下記の記事に修正のパターンが詳細に書いてあるおかげですぐに解決できました。 https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/ mabl(E2EテストSaaS)のテストを通す mablではユーザーがよくやる操作をテストをしています。 これにより、ユーザーが操作する重要な機能の基本シナリオをカバーしました。 このテストが通れば大きなバグのリスクは少ないだろうという状態になるかと思います。 stg環境リリース && 動作検証 stg環境では自動テストだけでは確認できない、パフォーマンスの検証や実際のリリースに問題ないかなどを確認しました。 stg環境はデータ量的には本番よりすくないためパフォーマンス検証は環境としては、不十分なところもあり今後環境を整備していかなくてはと考えさせられました。 Rails 7, Ruby 3の気になる機能 今後使う可能性が高い機能や個人的に気になる機能を紹介できればと思います。 静的解析の追加 Ruby 3の大きな目玉はRBS、TypeProfが追加されたことかと思います。 これにより、静的型付け言語が可能になります。 RBS: 型情報を記述 TypeProf: 静的型推論ツール 並列処理 下記の並行・並列処理の新機能もRuby 3の目玉ですよね 個人的な興味で使ってみたいなという気持ちがありますが、かなり難しい機能でもあると思うので実際使うことになるかは現状不明な機能です。 Ractor Fiber Scheduler Active Record::QueryLogs Marginalia gemの機能が追加されたものでQueryにコメントを追加できる機能です。 デフォルトでクエリタグに「アプリケーション」「コントローラ」「アクション」の詳細が追加されるので 特定の問題があるQueryの影響調査などに使えそうだなと感じています。 やってよかったこと 開発の手札を増やせる 新しいバージョンになると新機能も追加されますが機能が削除されたりもします。 新しい機能は何かしらの必要性があり追加されますし、何かしら使わないほうがいい理由から機能削除されることがあるかと思います。 新しい機能は開発するうえで手段を増やしたり、負荷に耐えるための手段が増える可能性があり これにより不要な開発やスケールのためのやることが減る可能性があります。 また、先々に削除される機能を使い続けると最新のバージョンへの対応工数がいつのまにか膨れ上がるリスクもあり 定期的にチェックして良い書き方にしていく動きも大変ではありますが大切だなと感じました。 開発チームの体験向上 新しい機能や書き方などは試したくなります。 それが、バージョンが古いために使えなくて汚いコードなどになるのは個人的にかなりストレスになります。 今回大きなコストをかけることなくアップデートでき、開発体験を向上できたのでとても良かったです。 シンプルに最新の環境になるのは嬉しい 他の開発メンバーも最新の環境になったことを喜んでくれたり、開発メンバー以外にも環境を新しくしていく重要性を話してくれる機会もありとても嬉しかったです。 まとめ 今回はRails・Rubyアップデートについて紹介しました アップデート自体はがっとやった感じでしたが、今までプロダクト開発に関わったメンバーがしっかりテストを書いてきたからこそすんなりできたと感じた作業でした。 テストの重要性はRailsアップグレードガイドの最初にも記載されており、テストはアップデートをする際の重要な点だとあらためて感じました。 https://railsguides.jp/upgrading_ruby_on_rails.html#%E3%83%86%E3%82%B9%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%AE%E3%82%AB%E3%83%90%E3%83%AC%E3%83%83%E3%82%B8 自分たちが早く開発するためにはやはりテストの重要性は高いものだなと感じました。 今後のアップデートのためにもこの文化は守っていきつつ、よりリリースリスクを下げて積極的に改善ができる状態を作っていきたいなと思っています。
アバター
スマートキャンプでエンジニアリングマネージャー(EM)をしている瀧川です。 本記事では、訳あって助っ人で新規Webアプリの負荷テストをすることになり、複雑な仕様とタイトなスケジュールのなかFloodというサービスと出会い事なきを得た話をしようと思います。 今回のケースではFloodがマッチ度高くかなり助かりましたが、活躍できる用途は限られる印象もあるので、一事例として見ていただき、後半でメリデメにも触れていこうと思います。 ことの発端 Floodとの出会い Floodとは Flood Elementとは Floodを使ってみる 料金体系 使ってみた感想 最後に ことの発端 現在スマートキャンプではオンラインイベントプラットフォームを新規開発しており、正式リリースに向けて機能改善を進めています。 そして直近では改善のためのアクションとして、小規模なイベントを開催してユーザーのFBを受けたり、データを見て改善ポイントを洗い出していました。 しかしそこで問題が起きました。 最初は社内のみで10人程度のイベント、次に50人、500人...といった具合で少しずつイベントの規模を大きくしていく戦略だったのですが、すぐにパフォーマンス問題が浮き彫りになりました。 ユーザーから見ると、チャットをしても反映に1時間かかる、新規ログインができないなどなど。 インフラとしては、アクセスユーザー数に対して不釣り合いなほど大量にスケールアウトしたサーバー郡。 これまでの開発で0-1フェーズの経験者が少なく、非機能要件を軽んじてきてしまったということでしょう(反省点1)。 そしてイベントのスケジュールが厳密に決まっていて、集客も動いておりリスケが困難だったため、緊急で助っ人として私も入ることになりました(反省点2)。 とてもあるあるな話で、良くないプロジェクトマネジメントでしたが、反省は次に活かすとして、そんなこんなで、 初めて触るアプリケーションのボトルネックを短期間で調査 して修正することになりました。 Floodとの出会い アサイン当初は、仕様をざっくり把握して、jMeterかなにかでユーザーシナリオ作って回せばいいよねと思っていたのですが、以下の理由で頓挫しました。 (かなり粒度の細かい理由で恐縮ですが) WebSocketを中心とした複雑な手続き Ruby on RailsでStimulusReflexなどを利用した動的なUI変更 オンラインイベント用のアプリケーションのため、リアルタイム性のある機能が複数存在しており、それらをWebSocket中心に実装していました。 かなり大々的にWebSocketで実装されていたため、仕様の把握やリクエストパラメータとレスポンスの一覧作成などが困難だったのが1つ目の理由です。 (そもそもこのあたりがパフォーマンスに影響を与えている予感はありました) また上記と併せて、アプリケーションはRuby on Railsで作られているのですが、StimulusReflexやCableReadyというGemを使っていたのも負荷テストを難しくさせる要因でした。 Action Cable, CableReady, StimulusReflex、ViewComponentを組み合わせると、サーバーからのイベントをトリガーにユーザーのUIを動的に変更する、リアクティブな実装が可能になります。 (最近でいうと界隈で話題になっているHotwireが近いかと思います) これにより実装としてはシンプルになる一方で、リクエストとレスポンスの形式がGemによってブラックボックス化してしまいました(一時的なIDがGemによって付与されたリクエストなど)。 またレスポンスに含まれているViewComponentからの値取得が先々必要になるような手続きがあったりと、テストの実装を難しくしていたかなと考えています。 そういった難解さをいったん無視するために、ユーザーに近い上位のレイヤーで負荷テストをしてざっくりとネックになっている範囲を絞り込むのが良いかなと考え、そんな中出会ったのがflood.ioになります。 Floodとは Floodは負荷テストを分散実行できるプラットフォームで、jMeterやGatlingで書かれたユーザーシナリオを分散実行することで大規模な負荷テストを可能にするサービスとなっています。 www.flood.io その特徴としてあるのがSeleniumや独自開発しているElementといったブラウザレベルのテストツールにも対応していることになります。 ブラウザレベルのテストはjMeterやGatlingといったツールでのテストと比較し、必要とするマシンリソースが多くなるため、実行環境を用意・管理するのが困難になります。 しかしFloodでは簡単に分散実行できる仕組みが用意されており、効率的にマシンリソースを使うことができます。さらにSeleniumやElementと組み合わせることで手軽かつ効率的にブラウザレベルのテストを実行できるという点が最大のメリットになるかと思います。 (各種テストのProsConsについて、Floodのドキュメントにわかりやすくまとまっているのでぜひこちらも参考にしてください Choosing a tool - Guides Flood Elementとは ブラウザレベルの負荷テストをするためのツールとしてFloodのチームが開発しているのが、OSSのFlood Element(以降Elementと表記)です。 ※ 余談ですがFloodは2017年にTricentisに買収されているようです。 element.flood.io ElementはFloodで動かすだけではなく、ローカル環境でも簡単に実行でき、デバッグが容易です。 またスクリプトは、デフォルトでTypeScriptで記載でき、Puppeteerのようなインタフェースでかなり取っつきやすいものとなっています。 コマンド例 # Initialize element init . ls # element.config.js example.perf.ts node_modules package.json tsconfig.json yarn.lock # --no-headless: ヘッドレスブラウザではなく、実行時にブラウザが起動し動作する。デバッグ時に有効。 element run ./example.perf.ts --no-headless # --mu: Multiple Users、TestSettingsでstagesのtargetが複数になっていた場合、複数ブラウザで実行される。ユーザーが重複して実行されないかデバッグに有効。 element run ./example.perf.ts --mu いくつかTipsを含めたサンプルスクリプトを以下に記します。 シンプルですね。 example.perf.ts import { step , TestSettings , TestData , By , beforeAll , afterAll , Browser , ENV , Until } from '@flood/element' export const settings: TestSettings = { loopCount: Infinity , // 実行失敗時にスクリーンショット screenshotOnFailure: true , // ブラウザの指定 browser: 'chrome' } const vars = { targetHost: 'https://challenge.flood.io' , usersFile: './users.csv' , // Floodで分散実行する際の設定値、ユーザーを重複なく分散するのに使用 // 1GridあたりのNode数 nodesPerGrid: 10 , // 1NodeあたりのUser数 usersPerNode: 50 } interface User { email: string password: string } export default () => { // 以下はFloodで分散実行した際に、ユーザーを重複なく割り振るための実装 // Floodには複数のGridとその中に複数Nodeを持ち、実行時に環境変数からIndexを取得できる const gridIndex = ENV.FLOOD_GRID_INDEX const nodeIndex = ENV.FLOOD_NODE_INDEX const nodesPerGrid = vars.nodesPerGrid const usersPerNode = vars.usersPerNode const startIndex = ( gridIndex * nodesPerGrid * usersPerNode ) + ( nodeIndex * usersPerNode ) const currentIndex = startIndex + ENV.BROWSER_ID // Userデータ読み込み TestData.fromCSV < User >( vars.usersFile ) . as( 'user' ) .filter (( u , i ) => { return currentIndex == i } ) // 実行がループするたびに実行される beforeAll (async browser => { // Basic認証 await browser.authenticate ( 'hogehoge' , 'fugafuga' ) await browser.visit ( ` ${ vars.targetHost } /events/ ${ vars.event.slug } /login` ) // Elementが表示されるまで停止 await browser.wait ( Until.elementIsVisible ( By.css ( "h1.title" ))) // スクリーンショット保存 await browser.takeScreenshot () } ) step ( 'Login' , async ( browser: Browser , user: User ) => { console .log ( `[LOG] Envs(Place: ${ ENV.FLOOD_GRID_INDEX } - ${ ENV.FLOOD_NODE_INDEX } - ${ ENV.BROWSER_ID } )` ) console .log ( `[LOG] LogIn(UserEmail: ${ user.email } )` ) const emailInput = await browser.findElement ( By.id ( 'user_email' )) await emailInput. type( user.email ) const passwordInput = await browser.findElement ( By.id ( 'user_password' )) await passwordInput. type( user.password ) const submitButton = await browser.findElement ( By.css ( 'input[type="submit"][value="ログイン"]' )) await submitButton.click () } ) } users.csv email,password,role user_0@example.com,asdf1234 user_1@example.com,asdf1234 user_2@example.com,asdf1234 user_3@example.com,asdf1234 Floodを使ってみる 実際にFloodでElementを分散実行する設定を見ていきましょう。 まずスクリプトファイルやユーザー情報など関連するファイルをすべてアップロードします。 ※ この際に複数TSファイルがあると正しくEntrypointを特定できず実行が失敗する可能性があるので気をつけてください。 必要に応じてSLOも設定できるようです。 ここで分散の設定をすることになります。 DemandはFlood側のインフラを利用し実行します。 Demandの場合は3リージョンまでの制限があり、Users per Regionが500usersなので、最大1500usersでの負荷テストが可能です。 ※ 初期登録時だとUsers per Regionが50usersになっていましたが、サポートチャットで連絡し対応いただきました、参考までに。 Hostedは自前のAWSアカウントなどを紐づけておき、あらかじめFloodのUI上からGridとしてEC2インスタンスを起動しておき、その環境で分散実行できるものになります。 ちなみにFloodでいう、Gridはサーバーインスタンスの集合を表していて主にリージョンで別れていて、Gridの中のサーバーインスタンスのことをNodeとしています。 そしてテストが実行される仮想ブラウザがUserと表されています。 Hostedも無制限というわけではなく、1リージョン(Grid)につき10nodes、1nodeにつき50usersが上限となっています。 ※ 1nodeにつき50usersがElement(ブラウザレベルテスト)を安定して動かす限界値とFloodでは定義しているようです。 なので2000usersで負荷テストをするには4リージョン(Grid) * 10nodes必要ということになります。 また、Hostedの場合はGrid作成時にVPCなども指定できるため、Closedな環境に対する負荷テストも実行できるかと思います。 実行すると以下のような結果が得られます。 各種メトリクス、実行ログ、ステップごとの失敗率やスクリーンショットなどを確認できます。 料金体系 VUH(Virtual User Hours)という単位を基準に従量課金となっています。 VUHは、 稼働ユーザー数 * 稼働時間 / 100  と定義されています。 例えば以下の画像の例だと 500users * 1hours / 100 = 5vuh となります。 Standardプランだと1vuhは$4.5なので、この例だと 5vuh * $4.5 = $22.5 となります。 ※ 登録時に500VUHが無料で使えます。 使ってみた感想 ローカルでのスクリプト作成、Floodでの実行とトータルしてみたときに、負荷テストを実施するまでのコストが低かったです。 また今回の私のケースでは、クリティカルなパフォーマンス低下が起きていたのが500users〜2000users程度で小規模だったこともありFloodがマッチしていたかなと思います。 (それ以上多くのユーザーが必要になると、インフラの立ち上げも大変ですし、料金もかなりかかってくるかなと思います) 実際にjMeterで苦戦していたところで、Floodを導入し、数日であらかたのユーザーシナリオを作成し負荷テスト実行、ある程度ボトルネックとなっているアプリケーション機能を絞り込むことができました。 (修正自体もタフでしたが、なんとか無事乗り切ることができました、Floodに感謝) なので、FloodとElementの使い所としては、 少人数での利用が想定されるアプリケーションや最低限の性能保証を最短で得たいような場合 がいいのではと感じました。 またFlood自体はjMeterやGatlingの実行も可能なため、Elementでユーザーに近い負荷テストをし、ボトルネックとなっている機能を絞り込んだらjMeterやGatlingで実行するといった併用も良いのかなと感じました。 個人的にはとてもシンプルなサービスで好きでした! 最後に 今回複雑なアプリケーションの負荷テストをするためにFloodを使った事例を紹介しました。 かなりシンプルなサービスで便利なため、覚えておくといざというときに活きてくると思います。 Floodは負荷テストを分散実行できる、Flood ElementはE2Eっぽい感じで負荷テストを実行できる、リリース初期や少人数が利用するアプリケーションの性能保証に有効、とだけ頭の片隅に入れて帰っていただければ幸いです!
アバター
スマートキャンプ、エンジニアの入山です。 私は現在、弊社 BOXIL SaaS の開発部長を務めており、開発タスクの管理やチー厶・メンバーのマネジメントを中心に行っています。 また、インフラエンジニアとして各プロダクトのインフラ構築に携わっており、社内で一番インフラを知ってる人という立ち位置も担っています。 そんな私ですが、今年の1月に子供が産まれ、40日間(約1ヶ月半)の育休を取得しました。弊社男性エンジニアとしては、3人目の育休取得となります。 今回は、私が取得した育休についてのお話をご紹介します! また、エンジニア1人目の育休取得者である執行役員の過去記事も良ければご覧ください! tech.smartcamp.co.jp 育休について 育休取得に至った理由 弊社エンジニア組織の育休事情 育休取得期間 育休前の業務内容 育休への準備 業務関連 育児関連 育休中を振り返って 業務関連 育児関連 復職後に感じたこと 40日でチームやメンバーは変化・成長する 40日休むとさすがに浦島太郎状態になる まとめ 育休について 育休取得に至った理由 私は妻と(現在は子供と)関東に在住していますが、お互いに実家が関東圏ではなく、出産にあたって以下の選択肢がありました。 実家に帰省して里帰り出産 どちらに帰省するか 現住居での出産 両親のサポート有無 この選択肢は関東圏に限った話ではなく、現住居と実家が離れている方々は、ほぼ全員が悩むものだと思います。 どちらにもメリット・デメリットがありますが、初出産で不明・不安なことも多く、更にはコロナ渦という状況も考慮する必要があり、妻と何度も話し合いをして予定日の2〜3ヶ月前くらいまで悩みました。 そして、最終的に以下の理由が主な決め手となり、 現住居での出産 と 育休取得 を決意しました。 現住居が(偶然)産婦人科に近く、その産婦人科が良い病院だったこと 徒歩で10分程の距離 希望していた無痛分娩が可能で費用も安い (コロナ渦でも)出産立ち会いが可能 里帰り出産を選択することによるストレス要因を避けたかったこと (2人で里帰りの場合)どちらかは相手の両親と同居となるため、両親含め気疲れしそう (妻だけ里帰り場合)妻の実家に通うことになり、コロナ状況も踏まえると産後に子供に会えない期間が発生する可能性がある 育休を取るイメージが容易にできたこと 弊社エンジニア組織で2人育休を取得した実績がある 親のサポートはほぼ得られないが、育休を取得すれば2人で何とかできそうな気がした 2人で協力して頑張る決意を固めた(大事) 現住居での出産の場合、両親が泊まり込みで来てサポートして貰うという話も聞くのですが、出産のタイミングでコロナ感染者が増加していたことや両親の仕事や家庭の都合もあり、基本的には両親に頼らず2人ですべてやり切る選択をしました。 この選択については、 育休取得が前提 となっているため、育休が取得しやすい環境であることが本当に有り難いと感じました。 弊社エンジニア組織の育休事情 弊社エンジニア組織における男性育休事情は以下となっています。 育休取得率:75% 3人取得(4人出産) 取得者の1人は執行役員 エンジニア1人目の育休取得者は現執行役員であり、環境的にも雰囲気的にも育休が取得しやすいです。 育休取得期間 育休取得期間については、制度として数日〜数ヶ月まで基本的に自由に決めることができます。 私の場合は妻と2人で育児を行なう前提もあり、産後の退院に合わせて育休を開始して、1ヶ月の期間を目安に復職日を調整する予定としていました。出産が予定日から前後することも多く不明確なため、育休開始日や復職日は都度調整が必要です。 実際に私は出産前から退院までの期間で最終調整を行っており、当初1ヶ月を育休予定としていましたが総務の方のアドバイスもあり、1/24〜2/28(復職日:3/1)まで、 40日間の育休取得 に決定しました。 アドバイスは、 育休期間中は社会保険料が月単位で免除される が、中途半端な期間(完全育休の月がない)で復職すると 免除が受けられない という内容でした。私の例では、当初の予定(1ヶ月:1/24〜2/23)だと2/24に復職となり1月も2月も労働日が存在するため、 社会保険料が免除されず満額徴収される だけでなく、2月分の給料は残りの3営業日分しかないため、損をしてしまいます。そのため、2月末まで育休にして復職を3/1にした方が良いとのことでした。 上記は一例ですが、育休に限らず制度の理解不足で損をする可能性もあるため、総務の方や制度について詳しい方へ相談し、疑問点を解消しながら話を進めることをお勧めします。 育休前の業務内容 冒頭でも少し触れましたが、私はBOXIL SaaSの開発部長としてのタスクだけでなく、スポット対応のインフラ業務や開発部の共通基盤管理も担当しています。 育休へ入る前のタイミングでは、主に以下の業務を担っていました。 BOXIL SaaS関連(定常) タスク・スケジュール管理 他部署との調整 マネジメント チーム(3人×2チーム) 各メンバー 目標設定・評価 インフラ関連(スポット対応) Terraform管理・反映 プロダクト丸ごとのインフラ・運用移管(完了直後くらい) インフラも関連するパフォーマンス課題対応(緊急対応中) 共通基盤関連(頻度低) アカウント管理 全体的に他のメンバーへ急に任せられるものは少ないのですが、特にインフラ関連と共通基盤関連に関しては技術領域的な面や組織内での権限、属人化した仕組みなどの要因により、意図せず私に依存した業務が多く存在しました。 育休への準備 育休取得については、出産予定日の2〜3ヶ月前に決定し、上長や業務上関わりが深いメンバーを中心に周知を進めていきました。その後、1〜2ヶ月前からは業務の何割かを育休に向けた整理や引き継ぎに使い、基本的にすべての業務において私が不在でも最低限困らない状態を目指しました。 当たり障りのない内容が多いですが、育休に向けた準備や取り組みの一部をご紹介します。 (育児関連はやることリストみたいになっている…) 業務関連 属人化業務の標準化 ドキュメント化 環境や仕組みの整備・改善 他メンバーへの共有 なるべく実際に手を動かしてもらう 業務の権限移譲 基本方針は自チーム(BOXIL SaaS)のメンバーで補う タスク管理やチームマネジメント業務は、サブリーダーに一任(上長や他の部長・リーダーに頼らない) 他部署との調整やPJ推進は担当メンバーを中心に行い、全体管理はPdMに一任 直近で動いてるPJは担当をメンバーへ引き継ぎ 評価周りやメンバーマネジメントは、上長や他の部長に代行してもらう 会議体の整理 会議の目的や役割、出席者などを見直し 育児関連 情報収集 制度 産休・育休 給付金 子育て支援 税制・社会保障 病院 設備・対応(無痛分娩など) 費用 保育園 探索 保活 育児準備 名前検討 消耗品・生活用品 ウォーターサーバー(同僚のお勧め) 育休中を振り返って 業務関連 育休中に業務へ顔を出した機会は、正直2回ありました。 育休前にパフォーマンス課題の緊急対応中だったプロダクトの本番稼働 呼び出しではないですが、育休開始直後の本番稼働で気になったのでこっそり見てました(自己都合) 無事に本番稼働を見届けて一安心で育休へ 共通基盤(VPN)の障害 リモートワークでの開発環境アクセスはVPNを導入していますが、VPNへ繋がらない障害が発生し、エンジニア全体の開発に影響があったため、VPNの仕組みに一番詳しかった私にもヘルプ依頼が来ました 結果的には開発端末のセキュリティソフトのVUPに伴う不具合で、メンバーが発見・対応してくれました これ以外では、40日間一切業務に関与しておらず、slackもほとんど見ていませんでした。 事前準備が上手く機能した部分もありますが、各業務を任せたメンバーたちが頑張ってくれたおかげで育児に集中でき、本当に感謝しています。 育児関連 育児のトピックを振り返ると、以下のような出来事がありました。 出産〜退院 無事に立ち会い出産(分娩室のみ) 宿泊型産後ケア制度を利用して入院を2泊延長 授乳・沐浴の講習や夜間の授乳などを産婦人科で支援してもらえる制度(県や市が費用の一部を負担) 妻の体力回復と助産師さんの支援を受けながらの育児練習が目的 育休前半 産後の妻の体力が低下していたため、子守・授乳以外の全家事を担当 素人なので育児すべてが大変 夜間対応を試行錯誤 2人で対応したり、交互で対応したりを試すが2人共睡眠不足で辛い時期が続く 寝かしつけにバランスボール導入 育休後半 妻の体力回復に合わせて少しずつ家事を分担 夜間対応のスタイル確立 3時間の授乳間隔で 寝る→起こされる を繰り返すのが辛いと気付く 夜間は寝ずに朝まで対応→朝方妻に交代→昼まで寝る のスタイルに落ち着く ネムリラ(自動で揺れるやつ)導入で寝かしつけがより楽になる 1ヶ月検診・お宮参り・写真撮影 宿泊型産後ケア制度は、活用してとても助かったのでお勧めです。 また、子供の寝かしつけで最初はバランスボールを使っていましたが、後半はネムリラを導入して身体の負担がかなり楽になったのでそちらもお勧めです。 復職後に感じたこと 復職後に感じたことはいくつかありますが、特に強く感じたのは以下の2点でした。 40日でチームやメンバーは変化・成長する 変化としては良い面も悪い面もあったのですが、育休前にイメージしていたよりもチームが変わったなというのが率直な感想でした。 弊社では1週間を1スプリントとしてスクラム開発を行っており、毎週振り返りと改善に取り組んでいます。内部で一緒に取り組んでいると大きく変化している実感はあまりないのですが、毎週1つ改善していれば40日だと5つくらい変化が起きているはずで、それをまとめて体験すると「かなり変わったな」と感じます。毎週の改善をチームで積み上げていくことの大事さにあらためて気付きました。 また、自分が担っていた業務を各メンバーに任せたことで、メンバーの動き方に変化があったり、成長を感じられる側面もあり、強制的な不在きっかけですが視座の変化や各々の成長に繋がる良い機会になったのだと感じました。 実際、育休をきっかけに自分の手を離れた業務があったり、復職後に助かっていることも多いので、とても嬉しい変化や成長でした。 例えば自分がいる状況で中途半端に口出ししつつ権限や裁量を十分に渡しきれていない状態で任せるよりも、今回のように完全不在ですべて任せる方がメンバーには良質な成長機会になることをあらためて感じました。 今後メンバーに業務や役割を移譲する際は、中途半端ではなくメンバーが責任を持ってやり切れる環境を可能な限り用意しようと思っています。 40日休むとさすがに浦島太郎状態になる 育休前は満遍なくプロダクトの開発全体を把握していたはずの私ですが、復職時には何がどうなっているのか全く分からない状態になってしまいました。40日不在だったので仕方ないという部分はもちろんありますが、復職当初はロードマップやリリース報告、タスクリスト、Sprint Reviewの内容を追っていけば、すぐにキャッチアップできると考えていました。しかし、現実はそう単純なものではなく、しっかりとSlackで経緯を追ったり、人に説明して貰ってのキャッチアップが必要でした。 キャッチアップに時間が必要な要因としては、背景や経緯の欠如による情報の欠落が大きいと考えています。今までは背景や経緯がインプットできる状態になっていたため、安易に全体の把握や理解ができていたことに気付きました。 また、この情報の欠落は自分以上に他のメンバーが今まで暗黙的に感じていたのではないかとも思いました。各メンバーがタスクの背景や経緯をしっかり理解できる状態を作ることで、タスクへの理解も深まりチームとしてより良い動きができるようになると思うので、今後改善していきたいと考えています。 まとめ 今回は私が取得した育休についてのお話をご紹介させていただきました! 現在は復職から丁度1ヶ月が経過し、リモートワークだけでなく出社日でも子育てと仕事の両立に慣れてきました。 また、子供もすくすくと成長し、笑ったり喋ったりと日々人間味が増してきており、可愛いさに癒やされています。(もちろん辛いこともあります…笑) 育児は会社や家庭の環境にも大きく左右されるものなので、参考にならない部分も多いかと思いますが、育休取得の一例として少しでも参考になれば幸いです!
アバター
こんにちは!スマートキャンプエンジニアの井上(エース)です! 皆さんは自社プロダクトに対してどのようにデータ分析をされていますか? データ分析基盤は構築されているものの、少なからず課題を抱えている企業も多いかと思います。 今回は弊社の BOXIL SaaS に 新しいデータ分析基盤を導入することになった ので、その背景や導入にあたって課題だったこと、その対策などを書いていこうと思います。同じようにデータ分析基盤を導入しようとしている方の参考になれば幸いです。 元の基盤の課題 クエリの乱立とデータ定義のバラつき クエリ作成依頼についてのエンジニアの対応コストが高い データ分析ツールの統一 パフォーマンス 新しいデータ分析(BI)ツールに求められたもの Lookerの選定理由 LookMLによる統一的な管理 ドキュメントの充実度 プルリクベースでの開発 実際のアーキテクチャの紹介 導入にあたって課題だったこと データ定義のバラつきへの対処 クエリに直接手入れしてメンテしているパターンへの対処 Lookerの社内での活用事例 導入して良かったこと 「クエリを書く」という概念がなくなった 細かいところに手の届くLooker 現状の課題 Redashを脱しきれていない まとめ 元の基盤の課題 まずもともとのBOXIL SaaSのデータ分析基盤を見てみます。 かなり簡素化して書いていますが、大まかにはこのとおりです。注目して欲しいのは下記のような点です。 定期処理サーバーであるdigdagによってDBのレプリカからBigQueryにデータが流れている ログ集約サーバーからBigQueryにデータが流れている それをRedashで分析している そして今回問題にしているのは右下のRedash部分です。この部分をリプレイスしたというのが今回の記事の要旨となります。 さて、概略を書いたところで、実際の運用に落としてみたときの問題点を整理していきます。 クエリの乱立とデータ定義のバラつき Redashをヘビーに使われている方々は共感していただけるかと思いますが、社内でRedashユーザーが増えてくると、各々が見たいデータを見たいように見るためにクエリやダッシュボードが乱立することになります。弊社についても、営業職のメンバーもクエリを叩いてデータを出したりするので(これは良いカルチャーなのですが)、多くのユーザーによって非常に多くのクエリが生み出されていました。 加えて弊社BOXIL SaaSのデータ構造は複雑で、後述するようにデータを使いやすいように加工などもしていませんでした。そのため集計ミスや条件漏れによって誤ったデータが使われたり、各事業部ごとにデータの定義がバラバラだったりして、それぞれのデータがどれくらい正しいのかの判断がしづらい状況にありました。 Redashのページネーション。合計でだいたい1000件くらいクエリがある計算。 クエリ作成依頼についてのエンジニアの対応コストが高い RedashはSQLベースで、データ抽出にも一定のスキルが必要なこともあり、各事業部から「こういうデータが見たい」と開発へ依頼が投げられることがよくありました。 しかし前述するようにデータが使いやすい状況になかったこともあって、毎回複雑なクエリを書く必要があり、エンジニアの作業コストがかかっていました。 データ分析ツールの統一 GA, Redash, DataStudioなど、弊社では多くのデータ分析ツールが使われています。それぞれの部署で異なるデータ分析ツールが使われることによって数値のズレやツール活用の属人化が進む恐れがありました。 パフォーマンス DBから流れてきたデータは、個人情報などのマスキングはしているものの、冗長化のためのテーブルジョインなどパフォーマンス向上のためのデータ加工はしておらず、ほとんどが未加工のデータとなっていました。つまりRedashからデータを閲覧するときには毎回JOINコストなどが発生することになります。 新しいデータ分析(BI)ツールに求められたもの 上記の課題をまとめた結果、新しいデータ分析(BI)ツールに求められるのは下記のような点となりました。 ユーザーがデータを正しく分析できる 集計ミスや条件漏れが起こらない 事業部ごとにデータの定義のバラつきが起きない クエリの依頼によるエンジニアの作業コストを減らせる できるだけ各ユーザーに集計をしてもらう Lookerの選定理由 さて、このような条件でスマートキャンプがLookerを選定した理由を挙げていきます。 LookMLによる統一的な管理 LookerはLookMLという独自の書き方でDB内のデータを定義します。 公式サイト から例を拝借します。 ########################################################## # FILE: orders.view.lkml # # Define the dimensions and measures for the ORDERS view # ########################################################## view: orders { dimension: id { primary_key: yes type: number sql: ${TABLE}.id ;; } dimension: customer_id { # field: orders.customer_id sql: ${TABLE}.customer_id ;; } dimension: amount { # field: orders.amount type: number value_format: "0.00" sql: ${TABLE}.amount ;; } dimension_group: created { # generates fields: type: time # orders.created_time, orders.created_date timeframes: [time, date, week, month] # orders.created_week, orders.created_month sql: ${TABLE}.created_at ;; } measure: count { # field: orders.count type: count # creates a sql COUNT(*) drill_fields: [drill_set*] # list of fields to show when someone clicks 'ORDERS Count' } measure: total_amount { type: sum sql: ${amount} ;; } set: drill_set { fields: [id, created_time, customers.name, amount] } } SQLに慣れ親しんだエンジニアからすると「なにこれぇ?」となると思うのですが、実際に触ってみるとそこまで難しいものではありません。むしろSQLを知っていればすぐに理解できるかと思いますし、今まで苦労して毎回書いていたGROUP BY句が不要になり感動するかと思います。 LookerではこのLookMLによって統一的にデータ定義を管理します。ユーザーはこのLookMLに書かれた定義に従ってデータを抽出します。例えば上記の例で言うと、 total_amount というmeasureを指定するとSQLをユーザーが定義することなくamountの合計が出ます。 これの何が良いかと言うと、 SQLを書くのはユーザーではなくLookMLを管理するエンジニア だということです。RedashではSQLを各々が書くことによって圧倒的にデータ出しに自由度がありましたが、その反面データ定義が各々のSQLに依存することになっていました。その点Lookerではユーザーは出したいデータ項目をポチポチして組み合わせるだけで、SQLを意識することなく出したい表を作ることができます。SQLを触らないので、SQLの誤りによる集計ミスや条件漏れが発生することもありません。これによって、ユーザーのデータ定義は統一的に管理しつつ、エンジニアの対応コストを減らすことができます。 LookerのExploreイメージ 公式 から拝借。 ドキュメントの充実度 そしてこのLookMLの学習を補助するものとして公式のリファレンスがあるのですが、これがかなり充実しています。プロジェクトの概念から派生テーブルまで、丁寧に説明してくれています。エンジニアとしてはこの手のリファレンスが充実しているのは開発する際に助かります。ただ日本語で利用できるリファレンスが限られているのが玉にキズです。 プルリクベースでの開発 LookerはデフォルトでGitによるバージョン管理が利用できます。つまり上記のようなLookMLをGitで管理ができるということです。これによって不毛な先祖返りなどがなくなり、安全に開発できます。LookMLを管理するのは主にエンジニアなので、Gitとの相性も良いです。 個人的に良かった点として、Lookerではまず自分のブランチ上で一通りの要素が壊れてないかどうかチェックしてからプッシュできるということが挙げられます。例えばデータ定義を変更したことによってダッシュボードが壊れてないかどうかをチェックできます。既存のものを編集するのは誰だって怖いですからね。こういうのはありがたいです。 実際のアーキテクチャの紹介 さて、新しいデータ分析基盤を紹介します。といっても、変更点は右下だけなので、そのあたりに注目してもらえればと思います。 まずデータレイクとなるBigQueryからELTツールであるdbtがデータを抽出します。 dbtは内部でデータのジョインやデータをまとめたりしてデータ分析しやすいように加工します。 加工したあと再びBigQueryにそのデータを流します。 Lookerはその加工したデータをクエリ実行時に抽出します。 主なプロセスは上記のとおりです。 dbtというツールが新しく出てきましたね。これはELTツールの一種で、主にデータ加工を担当します。SQLでテストを書くことができたりマクロを組むことができたり色々と便利なツールです。ここではあまり紹介しませんが、いつか機会があれば中で具体的に何をやっているのか紹介したいです。dbtについて詳しくは こちら。 こちらの新基盤の作成にあたって必要だったのはdbtとLookerの開発でした。開発者はほとんど私一人だけという感じでしたが、先輩エンジニアの瀧川さんの補助もあり、 およそ二ヶ月ほどで実装は完成 しました。 特筆したいのは、私自身はLookerを一度も触っていなかったことです。SQLの経験はあるものの、BIツールを触ることすら初めての私が二ヶ月でこの基盤を作れたのはLookMLの分かりやすさやドキュメント性に助けられたことが大きいかと思います。 変なところがあればすぐに教えてくれる。 導入にあたって課題だったこと データ定義のバラつきへの対処 LookMLによってデータ定義が一元管理できるというのがLookerのいいところです。 しかしLooker導入にあたってはそれが問題となることがありました。 それぞれのデータの定義について調査していくと、こっちの部署ではカウントするのにこっちの部署ではカウントしないというような定義のブレが見られたことです。これはもともとRedash上で各々の部署がデータ定義をしていたのが原因としてあります。 例えばBOXIL SaaSでは資料請求をしたユーザーの流入を分析して見ており、オーガニックや広告、メルマガなどの流入源の切り分けが存在します。しかしながら、特にオーガニックの定義については各部署間で違ったデータ定義をしていて、数の相違が生じていました。 しかしLookerに移行するうえでは、データ定義はできるだけ統一したいというのがエンジニア側の意見です。ただ一方的にデータ定義をしてしまうと事業のデータ分析に混乱をきたすことになるので、最適な落とし所を見極める必要がありました。 その対応として私が実行した手順が下記です。 既存の各部署のオーガニックリードの分析に使っているSQLを洗い出す その違いをドキュメントにまとめる 上記ドキュメントで各部署の責任者に現状把握をしてもらう Lookerでどうデータ定義するかについて各部署の責任者と合意を得る 特に気を使ったのが4でした。異なるデータ定義をしている以上、それには理由があるはずです。そこをヒアリングしてしっかりデータ定義に落としていきました。 クエリに直接手入れしてメンテしているパターンへの対処 スマートキャンプ社内のRedash上には特別多くの人から使われているクエリがありました。それはリードの流入元の切り分けから課金リードの絞りこみまで一元的に行っているいわば 神のようなクエリ でした。 この神クエリ、実は月一回程度更新が入りまして、例えばリードの流入源として新しい切り分けが追加されたときなどは、 ビジネスサイドの人が直接CASE文をいじって更新をする ということをしていました。 これが定期的に人の手によって手入れされているという辛さ。 さて、これをLookerに移行するとなると問題があります。それは、そのままの運用をするとビジネスサイドのユーザーがLookMLを触る必要があるということです。 エンジニアではない方にLookMLを管理してもらうのは、定義の信頼性担保などの観点で懸念があるので、私達が考えたのはスプレッドシートで管理してもらうというやり方でした。 BigQueryにはGoogle Spread Sheetを直接、表として読み込むという機能があります。それを使って、BQ上に保存されたテーブルをLookerで読み込むという方法を取りました。 スプシにCASE文の内容を移植して、ビジネスサイドの人も簡単に編集ができるようになりました。 utm_sourceなどのパラメータに流入源を判断するvalueが入っているような感じです。 Lookerの社内での活用事例 早速社内でもLookerは活用され始めています。例えば毎週のBOXIL SaaSのスプリントレビューではLookerのダッシュボードを使って状況が共有されています。 毎週共有されているダッシュボード(参考程度に)。 ダッシュボードに対してフィルターがかけられたり、ダッシュボードからExploreに移行してさらに詳細に分析したりなどができるので、データ分析体験として非常に良いものだと感じています。 導入して良かったこと 「クエリを書く」という概念がなくなった クエリを書かずにデータ分析を行える。これが当たり前にできるのが何よりLookerの凄さだなと感じました。これまでRedash上で分析したいデータごとにクエリを書いていたのが、dimensionを組み合わせるだけで思ったとおりのデータが出せるのはデータ分析の体験としてはとても良いです。 細かいところに手の届くLooker 開発をしているとJOINによってテーブルが膨らんで、でもその中でidでDISTINCTしつつ平均や合計を求めたいときなどがあると思います。そういうときはLookerの avg_distinct や sum_distinct を使えばすぐにできたりします。 あと私のお気に入りの機能は pdt(persistent derived table) )です。これは一時テーブルを永続化できる機能です。例えば集計用のテーブルや不要な列や行をフィルターしたテーブルを保存しておけます。これによって複雑なJOINを毎回することなく、すぐにデータを取り出すことができたりします。 さらにincremental pdtという機能もあります。例えばテーブル更新時にレコード作成日が最新日の行だけ追加することで、テーブルをまるごとDELETEしてINSERTする必要がなくなる、というような機能です。BOXIL SaaSの分析ではこれをログ用のテーブルを保存するために使っています。 このようにLookerの開発体験はすごく良く、とても細かいところに手が届くなあという印象です。 現状の課題 Redashを脱しきれていない 脱Redashができたかのようなタイトルなのですが、現状、Redashを完全に脱してLookerに移行できているわけではありません。 これはビジネスサイドの活用が進んでいないことが原因としてあります。一部の人にはLookerのアカウントを渡しているのですが、すべての人にアカウントを渡しているわけではないので、まだまだRedashユーザーが多いです。 この原因としては下記のようなことが挙げられるかと思います。 ユーザーがLookerの使い方に慣れていない Lookerの中で使えるデータ項目がどういうデータなのかユーザーに分かってもらえていない Lookerが高い 1は定期的にLooker講座を社内で開いてLookerの使い方をビジネスユーザーに周知しています。 2は現状の課題としてあります。こちらはこれまでバラバラに定義していたり、ドメイン言語が統一されていなかったことによる弊害かと思います。このあたりの課題の解決策は検討中です。やるとするなら、ビジネスユーザー向けにLookerデータ項目について勉強会を開催したり、ドキュメントにまとめたりといった対策でしょうか。 3についてなのですが、Lookerは高機能ゆえか料金が高めです。これもLookerがビジネスユーザーにまだまだ使ってもらえていないことの原因としてあるかと思います。 まとめ いかがだったでしょうか。今回脱Redashを目指す意思決定をしたスマートキャンプですが、まだまだLookerへの完全移行までは時間がかかると見込んでいます。 実はLookerに移行しようと社内で考え始めたのは去年の今頃ぐらいで、実際にここに来るまでには1年ほどかかっています。それほどデータ分析基盤の移行はハードで時間のかかるものだということですね。 これからもスマートキャンプはデータドリブンな会社を目指していきます。私達の事業に興味があれば下のリンクから採用ページも見てみてくださいね!
アバター
こんにちは!スマートキャンプエンジニアの中田です。 普段業務では BOXIL SaaS の開発に従事しています。 突然ですが皆さんはスキーマ駆動に開発されてますか? 直近、BOXIL SaaSにOpenAPIを導入しスキーマ駆動開発を始めたので、今回はその紹介記事です。 導入の経緯や利用方法、メリット等についてご紹介していくので、導入や改善の参考にしていただけると幸いです! OpenAPI Specificationとは 導入の経緯 外部に公開するAPIを作ることになった とても便利なことに気づいた 内部利用のAPIの開発にも利用したくなった BOXIL SaaSでの利用方法 導入ツール OAS SwaggerUI Committee OpenAPIGenerator 導入時に意識したこと 導入で感じたメリット まとめ あとがき OpenAPI Specificationとは OpenAPI Specification(以下OAS)とは、REST APIの仕様を記述するためのフォーマットのことです。 OASはYaml or Json形式で定義でき、この定義が各種プログラミング言語に依存しない形式で標準化されています。 そのためSwaggerツールやその他サードパーティ製の関連ツールと組み合わせ、OASの定義を元に多様な言語でAPI Clientやドキュメントの生成が可能です。 ※ SwaggerはOpenAPIの前の名称。 公式 には OpenAPI と OpenAPI Specification が同義であるような記載がありましたが、本記事では説明の便宜上以下の意味で言葉を使い分けます。 OpenAPI Specification REST APIの仕様を記述するためのフォーマット(仕様書) OpenAPI OASでAPIの仕様を管理する開発の方式 導入の経緯 はじめにOpenAPIを導入するに至った経緯についてお話します。 外部に公開するAPIを作ることになった 私が直近で開発していたBOXIL SaaSの新機能が、 BALES CLOUD という弊社提供の別サービスにBOXIL SaaSで持っているリソースを共有したいという内容のものでした。また、その機能の将来的なビジョンとして、共有を社内サービスだけに閉じず外部のサービスにも拡張できるようにしたいという話もありました。 そこでチームメンバーと相談の末、OpenAPIを導入して開発することを決めました。 その導入の決め手となったOpenAPIへの期待値は以下のようなものでした。 公開APIを作るなら仕様を表したドキュメントが欲しい OpenAPIなら公開用ドキュメントの生成や管理が楽になりそう BALES CLOUD(公開APIを利用する側のサービス)にAPIクライアントの実装が必要 OpenAPIならクライアントコードもいい感じに生成できるツールがありそう とても便利なことに気づいた 実際に外部公開APIを開発するためにOpenAPIを利用してみての体験はかなり良いものでした。 期待値として挙げていた公開用ドキュメントとクライアントコードの自動生成は、周辺ツールと組み合わせることで難なく可能で開発工数も削減でき、OASにAPI仕様の定義を集約できることによる恩恵を多分に感じることができました。 内部利用のAPIの開発にも利用したくなった 外部公開APIの開発がきっかけで「OpenAPIを利用した開発をBOXIL SaaS内部で利用するAPIの開発にも適用したい」と思うようになりました。 内部利用APIへの適用には、前述の外部公開APIの項で挙げたものの他にも以下の期待値があり、内部利用APIの開発にもOpenAPIを適用することに決めました。 APIとフロントでのインターフェース定義のズレを改善したい OpenAPIでスキーマ駆動な開発をすることで定義が一元化され改善できそう APIのデバッグコストを下げたい OpenAPIではOASから生成したドキュメントからAPIをコールできるので便利になる BOXIL SaaSでの利用方法 次に、実際にBOXIL SaaSでOpenAPIをどのように利用しているのかについてご紹介します。 導入ツール OpenAPIの利用にあたり以下のツールを新たに導入しました。 SwaggerUI OASからドキュメントを生成できるツール Committee OASの定義とAPIの仕様に差分がないかRSpecで検証するためのツール OpenAPIGenerator OASからクライアントコードを生成できるツール これらのツールを利用したBOXIL SaaS OpenAPI開発の全体像は以下の図のようになっています。 全体の構成 OAS BOXIL SaaSでは上図の通り、外部公開APIについて記述する用と内部利用APIについて記述する用とでOASを2枚定義する運用をしています。 この運用は、外部公開APIと内部利用APIとで欲しいドキュメントやクライアントコードが異なるため、その棲み分けをする意図で行なっています。 SwaggerUI OASからドキュメントを生成するツールには SwaggerUI を利用しています。 公式から Dockerイメージ が公開されているので、それを利用しています。 // ...snip services : swagger-ui : image : swaggerapi/swagger-ui container_name : swagger_ui ports : - 9000:8080 volumes : - ./openapi/oas/internal/openapi.yaml:/usr/share/nginx/html/internal.yaml - ./openapi/oas/external/openapi.yaml:/usr/share/nginx/html/external.yaml environment : API_URL : ./internal.yaml WITH_CREDENTIALS : 'true' // ...snip ※ 環境変数の WITH_CREDENTIALS は、BOXIL SaaSでCookie(Session)認証を利用している関係で渡しています。 (ブラウザからAPIのリクエストにCookieの情報を付与できるようにするため) 実際にSwaggerUIで生成しているドキュメントが以下になります。 SwaggerUI (1) OASの定義に従って、定義されているAPIのパスを一覧化してくれます。 SwaggerUI (2) また、各パスの中に入ると、対象のAPIのコールができたり、req/resの型情報などの詳細が確認できます。 OpenAPIのドキュメント生成ツールの有名どころはSwaggerUIと ReDoc の2つです。 BOXIL SaaSでSwaggerUIを選択したポイントは以下でした。 ブラウザからAPIをコールできる機能がReDocのオープンソースには無かった(商用のReDocでは提供されているそう) OASを2枚運用している関係でSwaggerUIであれば参照するOASをブラウザから手軽に切り替えることができ都合が良い 個人的にUIはReDocの方が好みだったので迷いました。今回はOpenAPIへの期待値としてAPIデバッグコストの低減化があったため、ブラウザから楽に検証ができるSwaggerUIの方を選択しました。 Committee 今後OpenAPIを利用した運用を進めていく中で、「APIに施した修正をOASに反映し忘れたりするんじゃないか」という懸念がありました。 特にBOXIL SaaSでは開発初期からOpenAPIを導入しているわけではなく、これまでのAPI開発の一連の工程に新たにOpenAPI導入により必要な工程が加わる形となるため、先の懸念が現実化する可能性は大いに考えられました。 この懸念を解消するのに便利なツールに、Request SpecでAPIのreq/resの内容とOAS定義の整合性を検証できる Committee 、 Committee::Rails があったため導入しました。 Committeeでは、提供されるヘルパーメソッドをRequest Specで利用することで、APIのreq/resの内容とOASの定義にズレがないかを検証できます。 (Committeeの利用方法について詳しく知りたい方は 公式の利用方法 を参照ください) CommitteeをBOXIL SaaSでの開発形態に合わせてより快適に利用するため以下のような工夫をしています。 RSpec .configure do |config| config.include Committee :: Rails :: Test :: Methods config.include CommitteeHelper config.add_setting :committee_options config.committee_options = { schema_path : CommitteeHelper :: INTERNAL_PATH , old_assert_behavior : false , query_hash_key : ' rack.request.query_hash ' , parse_response_by_content_type : false } # hooks for openapi: :internal config.before( :all , openapi : :internal ) { overwrite_schema_as_internal } config.after( :each , openapi : :internal ) { assert_openapi_schema(expected_status) } # hooks for openapi: :external config.before( :all , openapi : :external ) { overwrite_schema_as_external } config.after( :each , openapi : :external ) { assert_openapi_schema(expected_status) } end module CommitteeHelper include Committee :: Rails :: Test :: Methods EXTERNAL_PATH = Rails .root.join( ' openapi/oas/external/openapi.yaml ' ).to_s INTERNAL_PATH = Rails .root.join( ' openapi/oas/internal/openapi.yaml ' ).to_s # Committee提供のassertメソッドのラッパー def assert_openapi_schema (expected_status) # 400番を期待する場合はCommittee::InvalidRequestが起こることを検証する if expected_status == 400 expect do assert_request_schema_confirm end .to raise_error( Committee :: InvalidRequest ) assert_response_schema_confirm(expected_status) else assert_schema_conform(expected_status) end end # Committeeの参照するOASを外部公開に切り替える def overwrite_schema_as_external RSpec .configure do |config| config.committee_options[ :schema_path ] = EXTERNAL_PATH end end # Committeeの参照するOASを内部利用に切り替える def overwrite_schema_as_internal RSpec .configure do |config| config.committee_options[ :schema_path ] = INTERNAL_PATH end end end 上記の工夫により、実際にOASとAPIの整合性を検証するRequest Specは以下のコードで書けるようになってます。 # 内部利用OASを参照したいRequest Spec RSpec .describe ' request spec (internal) ' , openapi : :internal do let( :expected_status ) { 200 } # アサーション時にこの変数が参照される it ' returns :ok ' do subject expect(response).to have_http_status(expected_status) end end # 外部利用OASを参照したいRequest Spec RSpec .describe ' request spec (external) ' , openapi : :internal do let( :expected_status ) { 200 } # アサーション時にこの変数が参照される it ' returns :ok ' do subject expect(response).to have_http_status(expected_status) end end コードを説明していきます。 BOXIL SaaSはOASを2枚体制で運用をしているため、外部公開APIのSpecか内部利用APIのSpecかによってCommitteeの参照OASを切り替える必要がありました。 その切り替えに必要な振る舞いを以下の記述により簡易化しています。 (RSpecのメタデータを使って openapi: :internal スコープであれば内部利用のOAS、 openapi: :external スコープであれば外部利用のOASに参照をスイッチしている) config.before( :all , openapi : :internal ) { overwrite_schema_as_internal } config.before( :all , openapi : :external ) { overwrite_schema_as_external } また、「スキーマの整合性検証忘れ」を防止するために、 openapi: :internal 、 openapi: :external スコープ内では after(:each) でフックしてテストケースごとに自動で検証が走るようにしています。 config.after( :each , openapi : :internal ) { assert_openapi_schema(expected_status) } config.after( :each , openapi : :internal ) { assert_openapi_schema(expected_status) } BOXIL SaaSの開発形態にあわせてCommitteeをよしなにラップすることで、かなり便利に使えています。 OpenAPIGenerator クライアントコードの生成ツールには、 OpenAPI Generator を利用しています。 OpenAPIGeneratorも、SwaggerUI同様に Dockerイメージ が公開されているためそれを利用しています。 運用している2枚のOASで、それぞれ以下のように生成を仕分けて利用しています。 内部利用APIのクライアントコード TypeScriptで生成 BOXIL SaaSのフロントエンドで利用 外部公開APIのクライアントコード Rubyで生成 Gem化してBALES CLOUDで利用 外部公開APIのクライアントGemは現時点ではGitHub Packagesを利用して社内でプライベートに管理しています。 APIを完全に外部公開するタイミングで、将来的にはこのGemもパブリックに変更する予定です。 OpenAPIGeneratorで生成したコードを利用したプライベートGem 導入時に意識したこと 導入にあたってはとにかく「恩恵を受けやすい環境を整えること」を意識しました。 現在BOXIL SaaSの開発に携わっているメンバーは10名程とそこそこ多く、このように新規で導入したツールについて30分時間を取り全員に共有するとしても、単純計算で300分と中々のリソースが割かれます。 また既存のシステムに新たに乗せる形で導入しているため、中には「既存の開発方法の方が遥かに良かったじゃないか!」と導入に納得感を得られないメンバーも出てくるかもしれません。 OpenAPIはものとしてかなり便利ですがエコシステムも広大で情報量が多いため、導入時点でなるべく各ツールの利用方法を簡易化する工夫をし利用の流れを型化してドキュメントに起こしました。 そうすることで、利用方法を共有するコストを下げたり、チーム内で使い方にバラつきが出にくくなったり、導入初期時点ではOpenAPIに精通していないメンバーにも「なんか簡単で超便利」とOpenAPIによる恩恵を感じてもらい易くなったりと、OpenAPIを利用した開発が自然とチームに定着していくような環境を目指しました。 導入で感じたメリット 最後にOpenAPIの導入で感じたメリットについて紹介します。 基本的に導入の経緯の章に記載している内容と同じになりますが、以下のようなメリットを感じています。 APIの仕様が明確になる OASに他のAPIの仕様もまとまっているため、APIのつくりを型化/統一化できる SwaggerUIで仕様を一見して理解しやすい。デバッグも楽に スキーマ駆動に開発できる OASからドキュメント、クライアントコードが自動生成でき効率的 OASを修正すれば上記の生成物もまとめて修正できるため管理コストが低い 導入が直近で本格的な運用はこれからになるため、現時点では明らかに導入によるメリットの方を大きく感じており、デメリットはあまり感じていません。 今後運用が本格化するに連れ、新たに感じるメリットやもしくは運用が大変などのデメリットも出てくるかもしれません。 まとめ いかがでしたでしょうか? 今回はBOXIL SaaSに導入したOpenAPIについて書かせていただきました。 導入してからまだ日が浅く運用が本格化するのは今後になるため、実際運用してみての記事についてもまたいつか書ければ良いなと思ってます。 今のところ新規開発のAPIのみOpenAPIで開発している状態ですが、既存のAPIも含めマルっとOpenAPI化できるとより恩恵を受けやすくなると思うので、機会をみて徐々に定義を移していきたいなと思ってます。(長い戦いになりそうですが) 最後まで読んでいただきありがとうございました! あとがき 今回OpenAPI導入のアイデアを提案してくれたのは一緒に新機能の開発をしていた先輩エンジニアでした。 ビジネス要件を上手く噛み砕いて開発的な改善にも繋がった本提案は、一開発者としてとても勉強になりました。 スペシャルサンクスを贈ります!
アバター
初めに こんにちは、スマートキャンプ エンジニアの林です。 前回は私の 自己紹介記事 でしたが、今回は技術的な話をしたいと思います。 現在、Webフロントエンドを書くならNuxt.jsかNext.jsが選択される事が多いですが、皆さんはどちらがお好きですか? 私はVue.jsを使用したフロントエンド開発の経験が長いので、Nuxt.jsに親和性が高く、Next.js(React.js)の時代とされる今でも積極的にVue.jsを追いかけています。 そこで今回は旬なフレームワークであるNuxt3について書いていこうと思います。 TL;DR Nuxt3のNitroによってどれくらい早くなったか検証をしてみた。 サーバー側からのAPIへのレスポンス速度がNuxt2に比べて良くなったことが観測できた。 クライアント側からのAPIへのレスポンス速度の上昇は観測できなかった。 Nuxt3とは 今年の12月にNuxt3のパブリックベータがリリースされたことはご存じの方も多いかと思いますが、あらためてNuxt3についておさらいしたいと思います。 公式サイトを覗いてみるとこんな記述がありました。(DeepLを使用して日本語になおしてみます) Vue 3で次のアプリケーションを構築し、ハイブリッドレンダリング、パワフルなデータフェッチ、新機能を体験してください。Nuxt 3は、Web開発をシンプルかつパワフルにするオープンソースのフレームワークです。 Nuxt3はvue3で書かれていてさまざまな新機能が追加されていることがわかります。 具体的にどんな機能が追加されているかに関しては他の記事に譲ります。 そのまま、少し下にスクロールして読みすすめると、Nitro Engineという新しいサーバーエンジンついて以下のように言及されていました。 You can deploy this output on any system supporting JavaScript, from Node.js, Serverless, Workers, Edge-side rendering or purely static. (中略) The foundation of the Nitro server is rollup and h3 : a minimal http framework built for high performance and portability. NitroはNode.jsだけじゃなくてServiceWorkerやサーバーレス環境でも動作して、さらにh3という軽量のhttpサーバーが使われているようですね。 H3 「ふーん、Nuxt速くなったのかー!すげー!」 と終わらせてしまいたいところなのですが、 今回はNuxt3で新たに導入されたNitroエンジンで作ったAPIのパフォーマンスをNuxt2で作ったAPIと比較しながら調査していきます。 このような計測は初心者なので、気になるところなどありましたらコメントお待ちしております。 Nitroとは 検証に入る前に、Nuxt3に初めて搭載されたNitroについて紹介していきたいと思います。 Nitroは以下の利点があると公式ドキュメントでは記載されています。 Cross-platform support for Node.js, Browsers, service-workers and more Serverless support out-of-the-box API routes support Automatic code-splitting and async-loaded chunks Hybrid mode for static + serverless sites Development server with hot module reloading Node.js環境だけじゃなく、サービスワーカやブラウザでも動作したり、ホットリロードで快適に開発できることや、内部にh3が組み込まれており、関数の返り値をオブジェクトにするだけで、レスポンスをJSON形式にできたりします。また、Promiseもサポートしているので、非同期処理も簡単に扱うことができるようです。 Nuxt3 Server Engine それでは、Nuxt2とNuxt3両者でどれだけコードの記述量を比較するために、 api/hello にアクセスが来たら'Hello World'と返却するAPIを作成してみます。 Nuxt2 Nuxt2ではserverMiddlewareを使用することでAPIサーバーを作成できます。またserverMiddlewareは他のNodejsフレームワークを使用して、拡張可能なので、今回は便宜上Expressを使用します。 import express from "express" ; const app = express(); app.get( "/hello" , function (req, res) { res.send( "Hello World" ); } ); export default { path: "/api" , handler: app, } ; Expressのインスタンス作成後、getを使用して'/hello'のルートを作成しています。exportする際にpathに'/api'、handlerにappを指定することで、 /api/* にアクセスがくると、関数が実行されるようになるAPIを作成できます。こうしてみると結構記述量が多い印象ですね。 Nuxt3 一方Nuxt3では'/server/api'ディレクトリに任意のファイル名でファイルを設置すると、それ自体がAPIのパスになります。 今回だとのケースだと/server/api/hello.tsとするだけでAPIルートを作成できます。便利ですね。 export default (req, res) => { return "Hello World" } ; Nuxt2の実装とは大きく違い、ただ関数を作って文字列を返すだけでAPIが作成できてしまいます。内部でjson形式のレスポンスに変換してくれているので明示的に記述する必要がなく非常にシンプルですね! ちなみに自動でJSONに変換している部分はH3を使用して実現されていますが、以下のような実装になっていました。 middlewareで渡された関数の返り値のtypeがstringだった場合は、html形式のレスポンスになり、それ以外はJSON形式に自動で変換される処理になるようですね。 https://github.com/unjs/h3/blob/main/src/app.ts#L92 const val = await layer.handle(req, res) if (res.writableEnded) { return } const type = typeof val if (type === 'string' ) { return send(res, val, MIMES.html) } else if (type === 'object' && val !== undefined ) { // Return 'false' and 'null' values as JSON strings if (val && val.buffer) { return send(res, val) } else if (val instanceof Error) { throw createError(val) } else { return send(res, JSON.stringify(val, null , spacing), MIMES. json) } } 他にもuseQuery、useBodyなどを使用してリクエストの中身を簡単に取り出すことができます。 import { useBody, useCookies, useQuery } from 'h3' export default async (req, res) => { const query = await useQuery(req) const body = await useBody(req) // only for POST request const cookies = useCookies(req) return { query, body, cookies } } また、ホットリロードによってコードを変更すると高速でビルドが走らせる事ができるため、 爆速でAPIサーバーを作成できます。 次は作成したこれらのAPIを使ってNuxt3とNuxt2を比較してパフォーマンスがどれだけ変わったか見ていきます。 パフォーマンス計測 それでは、計測に使用するコードを書いていきます。 計測に使用するコード async function timer(promise) { const start = Date .now(); await promise; const end = Date .now(); const time = end - start; console.log( `time: ${time} ms` ); return time; } <template> <div>averageTime: {{ averageTime }} ms</div> </template> まずはtimerという関数を作成しました。引数にPromise Functionを渡して実行時間を取得できます。 それではpages/以下にコンポーネントを作成し、Nuxt2、Nuxt3で10回APIコールを行った結果の平均時間を取れるコードを書いていきます。 Nuxt2 <template> <div> <div>averageTime: {{ averageTime }} ms</div> </div> </template> <script lang= "ts" > export default { name: "IndexPage" , async asyncData(ctx) { const result = await Promise.all( [ ... Array (10) ] .map((_, i) => timer(ctx.$axios.get( "http:/localhost:3000/api/hello" )) ) ); return { averageTime: result.reduce((prev, current) => prev + current) / 10, } ; } , } ; </script> Nuxt2ではasyncDataを使用することで、Nuxtインスタンスが生成される前にAPIコールを行なうことができます。Promise.allを使用することでAPIコールを並列で行った結果を取得します。 Nuxt2 Data Fetching Nuxt3 <script lang= "ts" > export default defineComponent( { async setup() { const result = await Promise.all( [ ... Array (10) ] .map(async (_, i) => timer(useFetch( "/api/hello" , { key: ` ${i} ` } ))) ); return { averageTime: result.reduce((prev, current) => prev + current) / 10, } ; } , } ); </script> <template> <div>averageTime: {{ averageTime }} ms</div> </template> Nuxt3ではasyncDataの代わりにuseFetchまたはuseAsyncDataを使用することで、Nuxtインスタンスが生成される前にAPIコールを行なうことができます。 今回は内部でuseAyncDataを使用しているuseFetchを使用することにします。 Nuxt3 Data Fetching これで準備が整ったので計測していきます。 検証 サーバー側とクライアント側の両方の動作を確認したいので、計測は2種類行います。 画面描画時(サーバー側) 画面描画後(クライアント側) Nuxt Lifecycle 結果はconsoleに表示されるので、あらかじめ Group similar messages in console のチェックを外しておきます。こうすることで1回と2回目のレスポンス結果が同一でも別々に表示してくれて見やすくなります。 上記の設定をしたことで、同一結果がグループ化されずに別々に表示されています。 画面描画時(サーバー側) ブラウザがリロードされたタイミングで処理が行われるので、5回ほどリロードしながら計測します。 Nuxt2で計測 1回目: averageTime: 16.2ms 2回目: averageTime: 14ms 3回目: averageTime: 15.8ms 4回目: averageTime: 13.5ms 5回目: averageTime: 12.8ms 5回実行した平均は14.46msでした。 ローカル環境で実行しているので当然ではありますが、普通に速いですね。 Nuxt3で計測 続いてNuxt3の結果をみていきます。 1回目: averageTime: 3.2ms 2回目: averageTime: 4.7ms 3回目: averageTime: 2.6ms 4回目: averageTime: 4.1ms 5回目: averageTime: 3.6ms 5回実行した平均は3.64msでした。 Nuxt2も速かったですが、更に速い結果がでました。 Nuxt3はNuxt2より約3.8倍も速い結果となり、パフォーマンスの大幅に向上が確認できました。 次は画面描画後(クライアント側)での動作確認も行っていきます。 画面描画後(クライアント側) 画面上に押されたらAPIコールを実行するボタンを設置して確認していきます。 // nuxt3 const handleFetch = async () => { return await timer(useFetch( "/api/hello" )); } ; // nuxt2 methods: { handleFetch: async () => { return await timer(fetch( "/api/hello" )); } , } <template> <button @click= "handleFetch" >再取得</button> </template> 5回ほどポチポチ実行します。 Nuxt2で計測 平均7.9msでした。 サーバー側の時より速いですね・・・。 Nuxt3で計測 平均10.9msでした。 ほとんど結果は同一で、クライアント側ではほとんどパフォーマンスの向上してないという結果になりました。 結果 サーバー側はNuxt3がNuxt2に比べ約3.8倍も良い結果でしたが、クライアント側ではほとんど差は見られないという結果となったことから、nitroによって作られたAPIサーバー自体が速くなったわけではなさそうでした。 ただ、サーバー側のパフォーマンスは向上していそうだったので、これだけでもNuxt3を使う価値はありそうですね。 こういった計測はなかなか慣れておらず、至らない点が多いかと思います。もしご指摘などありましたらコメントをお待ちしております。 感想 「Nuxt3にNitroが搭載されてどれだけ速くなったの?」と疑問に思ったことが、今回の記事を書くきっかけとなったのですが、Nuxt3自体のパフォーマンス向上もさることながら、開発体験が非常に良かったのが驚きでした。 例えば npm run dev で開発サーバーを起動する時間も、Nuxt2だと約4秒かかっていましたが、 Nuxt3では約0.6秒で起動でき、とても気持ちよく開発できました。 Nuxt2 Nuxt3 まとめ 本記事では、Nuxt3とNuxt2で作成したAPIサーバーのパフォーマンスを比較した結果をご紹介しました。 Nuxt2に比べ高速化・最適化されている部分が多いNuxt3でどんどん開発していきたいですね。 最後までお読みいただきありがとうございました! 宣伝 イベント情報 2/28に弊社開発チームのリモートワークコミュニケーションについてお話しするイベントを開催します! ご興味ありましたら以下のリンクから内容や参加方法についての詳細をご覧ください! smartcamp.connpass.com
アバター