TECH PLAY

エス・エム・エス

エス・エム・エス の技術ブログ

264

はじめに @emfurupon777 です。エス・エム・エスに入社したのが2022年1月なので、3年ちょっとたちました。ようやくエス・エム・エスで働いているのだという実感も得始めているところで、これまでに経験してきた環境とは実感の仕方が異なることに面白みを感じ始めています。 この感覚をもって、Slackに戦略コンサル出身の経営陣が作り上げた前々職での実感を『変態的に優秀な人たちに引っ張り上げられつつ搾り取られ続けているような感覚』(※これは最大限の賛辞のつもりです)と表現したところ、プロダクト組織の責任者である @sunaot からも『奇遇ですね。私も以前の職場(私の前々職とは同じ戦略コンサル出身の別人による経営)のときはそういう感覚でしたw』と返ってきたので、妙な納得感がありました。一方で、「なるほど @sunaotも異なる実感がありそうなので、やはりエス・エム・エスで求められることはこれまでの経験と異なるのだなー」と再認識し、マネージャーとして考えていることをポエムとして書いていきます。(あくまで一社員としての私見ですので、その点はご容赦ください) 視座をあげるということ VUCAなどという小難しい表現を用いるまでもなく、変化の激しい現代において。目の前にある今イシューだと見えているものに正面からぶつかって、砕けて、を繰り返していくだけでは、なかなか前に進むことができなくなる状況はまま発生し、『視座を上げて見つめ直してみて』(意訳ですが)と、1on1などの場で伝えたり、伝えられたりした経験を持つ方は多いのではないでしょうか。 マネージャーとしてはチームに求めるべきことだと理解はできるものの、視座という言葉の必要性をうまく言語化し、説明することに難しさを感じていました。受け手側も、『それはマネージャーであるあなたに必要なものであって、自分には関係ないのでは?』と咀嚼しきれないのではないでしょうか。(私自身、かつてそう感じた一人です) チームへの役割期待 少し話は変わりますが、ここで前提を2点おさえておきます。 1点目は、社内の”チーム”定義です。 エス・エム・エスにおけるチームは短期と中長期、主戦場と周辺、時間軸に対する成長へどう取り組むかを考えていくのが役割になっていて、担うことが期待されているのは主にこのような事です。 固有の文脈の解釈・評価 今期、半期の目標とKPI、そこへのプラン おや、、一般的に言われるマネージャーの役割と認識されている事の相応の内容が、エス・エム・エスでは、一般的にマネージャーの役割とされる内容の多くが、チームへの期待として明文化されていますね・・・ アウフヘーベン(止揚) つづいて2点目は、上位グレードに対する期待値です。 弊社プロダクト責任者の @sunaotが書いた社内ドキュメントの中にこんな記載があります。 答えがなく選択肢複数の中でアウフヘーベンするのが上位グレードのイメージ あれ?おやつの話ですか?あ、違った。 Google日本語辞書より引用 ある命題(テーゼ)と対立関係にある命題(アンチテーゼ)を統合し、より高い次元の命題(ジンテーゼ)を導き出す止揚(アウフヘーベン)の考え方を土台とした思考法があり、これを弁証法というそうです。 重要なのは、対立する2つの命題(テーゼとアンチテーゼ)に優劣はなく、片方がもう片方を打ち消すのではなく、統合され進化していくという点です。なるほど。 一見、矛盾や対立する要素を統合し、より高次の価値を創出するための重要な手法で、この考え方は、利益追求と社会貢献、短期的な目標と長期的なビジョンなど、経営における多くの課題に適用されるとのこと。 (一般的に)マネージャーとはなんなのか マネージメントとは「なんとかすること」というのはよく言われることで、その任にあたっている人は感覚的にもこの表現はしっくりくる気がしています。 ところが、「うちの会社のEM / PdM / PjMって何をする人なんですか?」という、特定のアクションによってマネージャーの役割が定義されているかのような質問を投げかけられることが多いように感じています。 なぜそう感じるのか。試しにAIにマネージャーの果たす役割を尋ねてみると・・・ 業績管理と目標設定 人材管理と育成 コミュニケーションと連携 モチベーション管理 etc. なるほど、確かにこれをやる人がマネージャーという感じの答えが返ってきて、確かに表層でわかりやすく観測できるのはこういうことかもしれないという気はします。 エス・エム・エスにおけるマネージャーとは エス・エム・エスのプロダクト組織でもEMという表現をすることや、プロダクトマネージメントグループが存在するため、それを担う人という意味で共通認識を持つためにPdMといった表現をすることはそれなりにあるのですが、各人が担う期待は均一ではなく、事業遂行に必要な能力と、それぞれの得意・不得意などによってグラデーションがついています。(あたりまえのことを言っていますね) 普段の業務では、『EMだからこのアクションをする』『プロダクトマネージャーだからこのアクションをする』といった職種に縛られた考え方はしていません。マーケットに向き合う上で必要なことを自らのスタンスで取捨選択し、優先順位をつけながら推進していくことが求められています。(もちろん、全てのタスクを自分一人で実行するのではなく、仲間の力を借りて実現していく必要があります)。 この役割は一般的な企業であれば『経営層』や『ボードメンバー』、場合によっては『役員』といった、会社上の機関として位置づけられる立場の者が担う割合が多いと感じます。しかし、エス・エム・エスは役員が少ない経営体制であることからも推測できるように、それぞれの社員に明確な権限移譲が行われている組織です。 この移譲を受けて事業を推進する主体がマネージャーなのだと私は解釈しています。エス・エム・エスでは組織階層の中でのポジショニングを表す表現は必要としていない実情があります。たとえば、最近多く使われるようになってきた印象の表現に”VPoE”がありますが、社内で議論をしていく中で、「なんか誰もVPoEを名乗る必要性を感じてないね・・」となる瞬間があったりします。 どういう取り組みが必要なのか 私個人の経験では『社長意識』、@sunaotの経験では『2ランクアップ』、そしてエス・エム・エスでは経営層との縦横の連携など、優れた経営を行っている組織では、何らかの形で視座を高める取り組みが推奨されていると感じます。 表現の違いはあれど、行き詰まったり迷ったりした際は、意識的に自身の視座を上げるか、あるいは(無理にでも)視座を上げてくれる人に積極的に関わっていく(例えば1on1を申し込むなど)ことで、アウフヘーベンを体現するための新たな視点が得られるのではないでしょうか。。 もちろん良書を読んでインプットするといったことも重要だとは思いますが、組織として事業を推進していくにあたって、対話を重ねていくのは必要不可欠です。この対話を疎かにせずに行動し続けることができるのであれば、それぞれ得意領域は違えどマネージメント適正はあり、経営的思考を歩んでいくことにも繋がっていくと考えています。 組織が成長する中で、時には矛盾や対立構造が生じることがあります。そんな時こそアウフヘーベンを意識し、それぞれのチームが発揮している価値を尊重した上で統合していく、そうした戦略的な役割を担う意識を持つことが最重要であると考えます。。 おまけ 最後に @sunaotの記載を紹介しておきます。 ここでいうマネジメントというのが、EMなのかアーキテクトなのかPdMなのかデザインマネージャーなのか、実情でいくとこれはどれでもいいなあというのが今の状況で、職種的適切さよりも個人能力依存の限界のほうが早く来ている印象がある 問題に取り組み、前へ進めることができているのならば、それは良いマネジメントでありバックグラウンドの選別をしている余裕はない いや、マジで余裕はないですw すべての事業領域で仲間を求めていて、求人票の表現としては例えばEMといった一般的な表現はとっていますが、細かい表現にこだわる必要はありません。実体として今回記載させていただいたように、”事業を推進するマネージメント”に興味がある方はぜひカジュアル面談で意見交換したいです!というくらい、私たちは仲間を求めています。
アバター
はじめに はじめまして。 人材紹介開発グループでweb履歴書作成サービス『履歴書できるくん』の開発を担当している松尾と申します。 2020年に新卒入社し、昨年度よりスタートしたweb履歴書プロジェクトでwebの開発を担当させていただいております。今回はそんな新規サービスの立ち上げからリリースまでの経緯と振り返りについてお話しできればと思います。 プロジェクト発足 転職活動において、履歴書の作成は転職活動の内定を左右する大変重要なプロセスです。それ故に多くの労力を必要とします。たくさんの文字を書かなければいけなかったり、少し難しい文章を考えないといけなかったり。さらに、弊社の人材紹介サービスを利用いただく場合は、転職活動をサポートするキャリアパートナーに作成した履歴書の画像を送付し、その画像に対してキャリアパートナーが添削を行うというフローで履歴書作成が行われておりました。 これにより、質の高い履歴書の作成は実現できていた一方で、システムがない中での運用は多くの時間と手間を必要としていたため、よりスムーズな転職活動のご支援に向けた改善が求められていました。 今回のプロダクトでは、上記の課題を解消し、求職者とキャリアパートナーの双方にとってより良い体験を提供することを開発の軸に据えました。 プロダクトでの解決 本プロジェクトでは履歴書作成から添削までを一貫して行えるWebサービスを開発しました。このプロダクトは、求職者がスムーズに履歴書を作成・提出できるだけでなく、キャリアパートナーとのやりとりも簡潔かつ効率的に進められるよう設計されています。 具体的な機能は以下の通りです。 自動入力機能と豊富な例文 住所検索APIを用いた住所の自動入力や、生年月日から学歴の入学・卒業年を自動算出する機能、弊社人材紹介サービスで取り扱う職種に最適化された資格一覧や例文一覧を取り揃え、履歴書作成にかかる様々な手間を削減しています。また、添削にかかるリソースも大幅に削減できる見込みです。 データの自動保存 履歴書は自動的に保存されるため、途中で編集を中断しても安心です。プライベートとの両立の中で、忙しい日常の隙間時間に履歴書の作成を進めることができます。 キャリアパートナーとのスムーズな連携 作成された履歴書は、キャリアパートナーに自動連携されます。通知を受け取ったキャリアパートナーはWeb上で履歴書を閲覧でき、リアルタイムで添削ができます。 PDFダウンロード 完成した履歴書はPDFとしてダウンロード可能です。電子書類としての提出のほか、コンビニでプリントアウトすることもできるため急な提出にも即座に対応できます。 これにより、求職者の作業負担を大幅に軽減しつつ、サービス全体としてのサポート品質を向上させることができました。 大変だったこと プロジェクトを進めるにあたって、いくつかの困難にも直面しました。特に印象的だったのは、不確実性の高い課題への向き合い方とプロジェクト状況に応じた意思決定です。 不確実な課題にどう取り組むか 今回の開発チームは私含め比較的キャリアの浅いメンバーで構成されています。そのため、ゼロからプロダクトを立ち上げるという経験が不足しており、「何から手をつけるべきか」「どこまで決めれば開発に進めるのか」といった基本的な判断に迷う場面が多くありました。 そのような中で意識していたことは、「不確実性の高い領域から優先して取り組む」でした。最も見通しが立っていない部分から調査・検証を行うことで、その後の判断や設計の前提となる材料を早い段階で得るように心掛けていました。 また、判断の精度を高めるため、シニアエンジニアとの壁打ちやステークホルダーとのコミュニケーションを積極的に行い、プロジェクトのフェーズに応じて「今私たちがやるべきことは何か」をチーム内で意識的にすり合わせるようにしていました。 このような試行錯誤を繰り返す中で、チーム全体が「完璧な見通しがなくても、小さく進めて調整すればよい」と考えられるようになり、不確実性を前提に前進できる自走力が徐々に育っていったと感じています。 スコープ調整と意思決定 こうした不確実性の高い課題に対して優先的に向き合いながらも、プロジェクト全体を前に進めるには、状況に応じた柔軟な意思決定が求められました。 実際にプロジェクトを進める中で、当初の計画にはなかったタスクや新たな課題が判明し、当初想定していたスケジュールでのリリースは現実的ではないという判断に至りました。そこで私たちは、現時点で実現できる最も価値のあるプロダクトとは何かを考え、リリースブロッカーを洗い出すことで、機能の優先順位を見直しながらスコープの調整を行いました。 結果的に、限られた時間とリソースの中で価値のあるリリースを実現できたということが、チームの大きな自信につながりました。 最後に リリースから間もない段階ではありますが、早速次のような成功事例が寄せられています。 履歴書の作成が心理的なハードルになっており、なかなか転職活動に踏み出せなかった求職者の方が、このツールを使って履歴書を提出してくださった 他社の人材紹介サービスと併用していた求職者が、履歴書作成までサポートする一貫したサービス提供を理由に、最終的に弊社を通じて転職を決めてくださった またキャリアパートナーからは、当初予定していた完璧なリリースができなかったことに対して 「自分たちが活用して意見を出していける、自分たちによってよりよいサービスになる」 機能追加をきっかけに、中長期的なご支援や定期的なフォローアップが可能となり、より一人ひとりに寄り添ったサポートができるようになった といった前向きなフィードバックをいただいています。 当初の計画からスコープを絞り込んでのリリースでしたが、限られたリソースと不確実性の中で「何を作り、何を作らないか」を判断し、プロダクトの価値を最大化するという経験ができたことは、今回のプロジェクトを通じて得られた最大の学びでした。 今回得た学びを活かしながら、求職者、キャリアパートナー双方の課題に向き合い、価値あるプロダクトを届けられるように引き続き取り組んでいきたいと思います。
アバター
エス・エム・エスのテックブログ編集チームの髙木です。 弊社のテックブログは2021年3月3日に1本目の記事が公開されており、今年で5年目になります。ちなみに1本目の記事はこちらです。 僕がブログ編集チームに参加したのは2023年4月からなので、いつの間にか2年が経ちました。記事自体はある程度コンスタントに出ているブログではありますが、うまくいった取り組みもあればうまくいかなかった取り組みもあります。このあたりをシェアできればと思います。 ブログ編集チームについて 弊社のブログは編集チームによって運営されています。各々が開発チームに所属しながら有志として活動しているようなチームです。したがってプロジェクトが忙しいタイミングでは参加できず、他のブログ編集メンバーにお願いするような状態で運営しております。現在は数人で運営しています。 役割としては、以下の4つです。 記事のテーマの提案 原稿の添削 はてなブログへの入稿やサムネイルの作成 社内への宣伝 うまくいっていないこと まずうまくいっていないことから共有します。うまくいっていないことがある前提でうまくいっていることを共有できたほうが現在の状態が把握しやすいと考えたためです。 自発的に書きたい人が出てくる仕組みづくり それなりにアクティブに投稿できている弊社のブログですが、これらのほとんどはブログ編集チームや採用担当から話を持ちかけることが多いです。比率的には 編集から持ちかけ:執筆者の持ちこみ=5:1 ぐらいの感覚です。 編集担当者からの執筆依頼がベースになっているため、スケールしにくい問題があったり記事がなくて投稿できない週が発生したりしています。わりとゆるい運営でやっているので大きな課題にはなっていませんが、投稿を安定させるためには自律的に投稿したいと思える仕組みづくりが必要かなと思っています。 また編集担当者からの持ちかけだと、相手の都合やモチベーションがないなど断られることもそれなりにあります。依頼をして断られるというのは当たり前です。当たり前なのですがやっぱり最初は精神がすり減ります。僕自身は2年ほど担当する中で慣れたのですが、慣れるまではしんどい気がします。そのため自律的に投稿者を募れる仕組みがあるとブログを運営するという意味で安定すると思います。難しいことだとわかりつつ今後も模索していきたいです。 技術的な記事が出にくい 弊社のブログは技術そのものにフォーカスした記事というよりもプロジェクトやプロダクトにフォーカスした記事が出やすい傾向にあります。このブログを愛読してくださっている方はご存知かもしれませんが、技術にフォーカスした記事は1年で数本しかでない傾向にありました。 ただ、昨年弊社のZenn Publicationが始動したことで状況が少し変わりました。 結果として技術そのものにフォーカスした記事はZenn Publicationで以前に比べると活発に投稿されるようになりました。 このことから考えるに、弊社の特性として技術的な記事が投稿されなかったのではなく、技術的な記事を投稿しにくい雰囲気があったり投稿までのステップが重かったのだと思います。Zenn Publicationは入稿までのステップが個人で完結するようになっていることで、気軽に投稿するというアクションが取りやすくなったのだと思います。 厳密に決まっているわけではありませんが、プロダクトや会社の情報を扱うものはテックブログ、技術単体にフォーカスした記事はZennという棲み分けができたことで、ジャンルによらずアウトプットがしやすい環境になったと思います。テックブログとしては技術的な記事が出にくいという課題は抱えたままですが、社としては技術記事がアウトプットされるようになったので良かったと思います。 うまくいっていること 週次ミーティングの運用 ブログ編集チームでは、週次ミーティングを行い以下を実施しています。 記事の進捗確認 記事の添削 記事の候補探し 進捗確認や添削などがうまくいっているというところもありますが、ミーティングをスキップせずに毎週取り組めていること自体がうまくいっていることだと思います。メンバー都合で参加できない週はありますが、誰かは必ず参加できるようなメンバーで構成できていることに意味があると思っています。毎週必ず実施し、スケジュールが把握できていることで結果としてブログ記事が定期的に出せているように思います。 異なるチームのメンバーで構成されているため情報が多い チームはそれぞれ状況が異なるため、持っている情報や見えている環境も異なります。そのため複数の所属でチームが構成されていることで、社内の情報が見えやすくなるように思います。現在は執筆依頼を前提にしたオペレーションとなっていることもあり、いろいろな人の状況が見えるようになっていることでアイディアを見つけやすくなっているように思います。 採用担当が絡むことで幅の広い情報が出る 採用担当と定期的にコミュニケーションを取るようにしております。採用担当は横断でいろいろなプロジェクトの現状を把握しているため、プロジェクトの状態に応じたアイディアをもらえることが多いです。 テックブログに採用の色が強く出すぎてしまうと、読み手にとって得られるものがなく意味のない記事になってしまうと思っています。それはこのブログを運営する我々にとっても広いインターネットの海で偶然にもこの記事にたどり着いてくださった方にとっても不幸なことです。そのため採用担当に関わってもらってはいますが、記事の内容については基本的に編集チームと執筆者で決めて、採用目的になりすぎないよう気をつけています。やっていることの工夫や反省が読む人にとって価値になると思うので、俯瞰的な記事アイディアをもらえる採用担当には継続的に関わってほしいと感じています。 編集担当者がばらついている 記事を執筆するに当たり、ブログ編集チームから1人が担当し執筆者をサポートしています。人数に余裕があるということもありますが、編集担当者が特定の個人に依存していないというのは良いことだと思っています。編集担当者がつくことによって記事の質は上がりますが、その仕組み自体をつくるにはどうしても人が必要ですし、特定の個人に依存していると同時に制作できる記事の数に限界があります。ブログ編集チームをアクティブに動ける人たちで形成できたので、記事を定期的に出せているのだと思います。 一方で編集担当者がつかないと記事を出せないということでもあるため、自分たちがボトルネックにならないように活動はしていければと思っています。 社内ドキュメントを利用したLLMによるネタ探し(試験運用中) ネタに困ったときには弊社のドキュメントをLLMにインプットとして与え、テックブログの記事として使えそうなアイディアを探させています。弊社は esa に技術的な取り組みや課題や考え方などさまざまな文章が保存されているため、その内容からアウトプットを得ようとしています。 記事にできなさそうなものがほとんどですが、たまによさそうなものが見つかったりしています。社内の取り組みを知ることもできており、役に立つかどうかはおいておいて今後も続けていきたい施策です。 この取り組みは、 @_kimuson の貢献が大きくいつも助けてもらっています。_kimusonが執筆した記事もいくつかでているのでよろしければ読んでみてください。 やっていないこと 記事の評価 現在は記事のPVや伸びたかという評価は行っていません。行っていないというか難しいからできていないというのが正しい表現だと思います。 インターネット上に投稿された記事の貢献とは、プレビュー数のようにわかりやすく数値で見えるものもあれば読者への貢献度など数値で見えないものもあると思います。1つの記事によって価値を最大化しようとすると検討のフェーズが挟まってしまい記事を出すことのハードルが高くなりすぎてしまいます。もし毎日100本の記事が生まれるのであれば実施したほうが良いと思いますが、今のフェーズでは月に数本しか記事は出ないので考えなくても良いと思います。 最後に 今回はテックブログ自体の運営やうまくいっていることなどを整理してみました。おそらく会社によってテックブログの運営や役割など多岐にわたると思います。今後も皆さんに役立つ記事を公開できればと思います。
アバター
井上大輔(いのうえ だいすけ)と申します。BPR推進部 キャリア横断開発グループメンバーとして、2023年にエス・エム・エスに入社いたしました。 もともとは保育士を目指し、保育士資格・幼稚園教諭二種を取得。その後、家庭の事情とIT分野への興味からIT業界へ転身し、営業職を経て、現在はエンジニア職でチームリーダーを務めています。 異業種からIT分野へ 私が育った地域では共働きの家庭が多く、年齢に関わらず子どもたちが集まって遊ぶ環境でした。その中で子どもの成長を支援したい考えを持つようになり、学童保育ボランティアの経験を経て短大に進学し、保育士・幼稚園教諭資格を取得しました。 しかし、家庭の事情により保育士を続けることが難しく転職を検討していたところ、親戚の薦めからIT分野へ興味を持つようになり、プログラマ系の専門学校へ入り直してからIT業界へ転身をしました。 専門学校卒業後に入社した企業で営業職の能力適正を見出され、営業に配属されました。 営業職では、お客様の課題を深くヒアリングし、その解決策を提案することにやりがいを感じ、顧客視点の重要性を学びました。この営業経験は、表面的な問題解決に留まらず、事業部と連携して課題の根本原因を掘り下げ、共通認識を持った上でシステム開発を進める現在の業務にも活きています。 転職活動とエス・エム・エス入社 一方で開発をしたい思いを諦めきれず、エンジニアを目指し転職。開発実績がない中、OA事務として入社し、業務改善ツールの開発を通じて社内経験を積み、念願のエンジニアへと転属しました。エンジニア転属後は、Salesforce顧客管理システムの開発を一通り経験。更なる成長を求めベンチャーへ転職し、Salesforceに加えAWSインフラなど幅広い技術を習得しました。 前職ではSalesforceの契約終了に伴い転職活動を開始。Salesforceの経験を活かしつつ、開発体制が整った環境で自身の成長を追求したいと考えていたところ、転職エージェントを通じてエス・エム・エスをご紹介いただきました。熊谷さんとの面接が、エス・エム・エスへの入社の決め手となりました(私が面接をしてもらった熊谷さんも入社エントリーを書いていますので是非ご参照ください!: 二つ返事で書いた「私のキャリア」と「転職決断話」 ) 熊谷さんからエス・エム・エスの人材紹介事業における業務基盤システムにSalesforceが採用されており、事業成長に伴う要求の複雑化・高度化に対応するため、共に課題解決に取り組む仲間を求めているというお話を伺いました。自身の営業と開発双方の経験が活かせると感じたこと、そしてアジャイル開発導入に向けた組織体制づくりが進められていることを知り、自身の成長に繋がる環境だと確信しました。 また、熊谷さんのエス・エム・エスでの取組みからエンジニア自身が主体となって課題解決に取り組んでいる話からもエス・エム・エスに魅力を感じ入社を決めました。 キャリア事業領域における私のチームの役割 キャリア事業領域は医療・介護/障害福祉業界の人手不足という課題解決を使命とし、人材紹介サービスを通じて課題解決に取り組んでいます。私が所属する開発チームは、医療・介護事業者の働き手が欲しいニーズに応えるべく、人材紹介サービスの求人情報を充実させるための機能を提供しています。 チームリーダーとしての役割 一般的な開発チームリーダーのイメージとして、責任範囲の広さから業務が集中してしまい、ボトルネックになりやすかったり、会議体が多くなるイメージがあるかと思います。 そこで、これらの課題についてはスクラムを導入し責任範囲をチームに分散することで解決しました。 予算管理や契約面など中央集権型組織としての必要最低限のマネジメント業務はリーダーに委ねられますが、ステークホルダーとの会議にメンバーも参加することで、課題への理解を深め実装時のリスクを事前に回避できたり、要件定義の時点からチームを巻き込んで調整窓口としての機能もメンバー自身が担うことで、リーダーがボトルネックになることなく、複数の開発案件を同時に実行できるようにしています。 (スクラムのイベントに関する具体的な取り組みはこちらをご覧ください: https://tech.bm-sms.co.jp/entry/2024/12/17/100000_1 ) 取り組んでいるチーム課題 私たちのチームは、スクラムで開発案件を進める中でこれまで見えてこなかったいくつかの課題に直面しました。 その中でも特に大きかったのが、チーム発足前に各メンバーが専任に近い状態で担当していた機能があり、ナレッジやスキルに偏りが生じていたことです。 この課題を解決するため、私たちは積極的にチーム内で話し合いの場を持ちました。 課題解決への第一歩:チーム改善MTGの活性化 まず取り組んだのは、チーム改善MTGをより活発にすることでした。「もっとこうすればチームがうまく回るのではないか」というアイデアが出ても、個人の発散で終わってしまうことがあります。それを防ぐため、メンバーが意見を出しやすい雰囲気を作るためのMTGを新たに開催することを提案しました。 このMTGでは、各メンバーが付箋を使って自由にアイデアを出し合い、それらを共有しながら議論を進めました。その結果、「ナレッジを蓄積する場所」や「ナレッジに記入するべき内容」について、チーム全員で合意形成を図ることができました。 ナレッジ共有の基盤:情報共有サービスesaの活用 チームで蓄積したナレッジは、情報共有サービスのesaを活用して一元管理しています。esaは、機能仕様だけでなく、利用者、そして利用者の運用方法についても記録するようにしています。 機能仕様: システムの設計や実装に関する基本的な情報はもちろんのこと。 利用者: どのような目的で機能を利用しているのか、どのような課題を感じているのかといった、ユーザー視点の情報。 利用者の運用方法: 実際にどのような手順で機能が使われているのかといった、具体的な利用状況。 これらの情報を共有することで、開発者側の視点だけでなく、ユーザーの視点や実際の利用状況を踏まえた改善活動に繋げることができます。 スキルの偏り解消への取り組み スキルの偏りを解消するための具体的なアクションとして、以下の2つの取り組みを始めました。 技術分野についての勉強会の開催: 各メンバーの得意な分野や興味のある技術について勉強会を開催し、チーム全体の技術力を底上げを目指します。 機能を全員で理解するためのグループワーク: 特定の機能についてチーム全員で集まり、仕様を読み解いたり、実際に触ってみたりしながら、相互理解を深めます。 これらの取り組みを通じて、チームのナレッジ・スキルの偏りの解消を目指しています。 チームリーダーとしてのやりがい エス・エム・エスの【高齢社会に適した情報インフラを構築することで人々の生活の質を向上し、社会に貢献し続ける】というミッションに対して、チームとして何をすることで貢献できるかを考え、事業部とコミュニケーションをとりながら課題を発見し、解決方法を見出していくことにチームリーダーとしてやりがいを感じます。 個人的なやりがい、楽しみ エス・エム・エスで仕事をする上で大きなやりがいとなっているのが、かつて目指していた保育士としての経験から、間接的ではありますが保育業界の労働人口増加や定着支援に貢献できていると感じられることです。自身はもう保育士ではない為、現場に直接かかわることはできませんが、保育業界がより良くなっていく為のシステム提供が出来ればと思い仕事に取り組んでいます。 おわりに 私たちのチームが所属するキャリア事業領域は、今後もサービス領域を拡大していく方針です。そのため、将来の事業拡大を見据えたシステム全体の最適化と、変化に素早く対応できるチーム作りが急務となっています。 チーム体制は発足したばかりで、まだ多くの課題があります。しかし、私自身もメンバーと共に課題を発見し、解決していく過程に大きなやりがいを感じています。 事業の目標や課題を深く理解し、システムを通じて社会に貢献していくことは決して簡単な挑戦ではありません。しかし、私たちと共にこの重要なミッションに情熱を持って取り組んでいただける方をお待ちしています(チームリーダー募集の詳細はこちら: https://open.talentio.com/r/1/c/smsc/pages/104978 )。
アバター
はじめまして。人材紹介開発グループで看護師向け人材紹介「 ナース専科 転職 」のWEB開発を担当している藤井と申します! 2024年4月に当社に入社してからあっという間に1年が経過しました。本稿では主にスクラムに関して入社当初に私が感じた課題と、課題に対して行ってきたアクションをご紹介できればと思います。 ※私を含めた開発を行うエンジニアチームと事業部のマーケター(主には集客に責任を持ちつつ、事業成長をミッションとするマーケティング組織)が度々登場するため、それぞれ「開発チーム」「マーケター」と呼ばせて頂きます。 スクラムの体制について 「ナース専科 転職」では以下のスクラムイベントを1週間スプリントで実施しています。 デイリースクラム スプリントプランニング スプリントレトロスペクティブ リファインメント(適宜) リリースが適宜行われる運用体制のため、スプリントレビューとしてまとまった時間をとって行うのではなく、タスクごとに担当者がマーケターと成果物の確認を実施しています。 入社時に感じた課題 私はチームがスクラムを取り入れて半年程度の頃に参画したため、当時はチームが徐々にスクラムに慣れてきている段階でした。その状況で私は特に「開発チーム内の透明性」と「開発チームとマーケターの距離」に改善の余地があると感じていました。 開発チーム内の透明性 デイリースクラムで対応内容の共有は行っていたものの基本的に個で動いていた 何がチームで課題となっているかの把握が難しかった 日中困った時に相談するのに障壁があった 開発チームとマーケターの距離 週1回の定例でタスク依頼の共有が行われる以外は基本担当者同士でやりとり マーケターはスクラムには未参加 開発チームもマーケターもお互いが何をしているのか把握しづらい 上記のような事象が発生していることでスクラムの三本柱である「透明性・検査・適応」が十分に機能し切れていなかったため、これらを改善することでチームとしてさらに成長することができると考えていました。 実践アクション 上述した課題を解決するために、「チームビルディング」「スクラムイベントの改善」「コミュニケーションの改善」の大きく分けて3つの観点から改善のアクションを実施しました。 チームビルディング スクラムガイドの読み合わせ スキルマップの作成 ドラッカー風エクササイズ ワーキングアグリーメント スクラムイベントの改善 デイリースクラム レトロスペクティブ リファインメント・プランニング(マーケターの参加) コミュニケーションの改善 開発チームとマーケターで1on1ミーティングの実施 オフラインイベントの実施 それぞれについて詳しく紹介していきます。 チームビルディング まず始めに、開発チーム内でメンバー間の距離を縮めると同時にスクラムに対する認識を合わせようと思いチームビルディングを実施しました。 ここでご紹介するチームビルディングは主に『アジャイルサムライ(Jonathan Rasmusson著 20011.7.16)』に記載の内容を参考にして行いました。 活動 内容 成果 スクラムガイドの読み合わせ スクラムガイドを元に現状のチーム体制になぞらえた資料を作成して読み合わせ 現状の課題とどうあるべきかについての擦り合わせを行うことができた スキルマップの作成 開発に求められるスキルを列挙し、そのスキルに対する習熟度への自信を回答 チームの強み・弱みの把握や困った時の拠り所の発見に繋がった ドラッカー風エクササイズ 自分は何が得意なのか・大切に思う価値は何か・何を期待されていると思うか・他のメンバーに何を期待するかを発表し合う メンバー間の認識を合わせると同時にモチベーションの向上にも繋がった ワーキングアグリーメント マインドとアクションの両側面で意見を出し合い、チームの約束事と大事にすることを決める より働きやすいチームにするためにお互い意識すべきことを話し合う良い機会になった スクラムイベントの改善 デイリースクラム デイリースクラムは状況報告の場になっていたため、スプリントの検査を適切に行うための場にすることを意識してアクションを実践しました。 改善前:デイリースクラムまでにまとめておいた昨日やったこと・今日やること・困っていることを共有 メンバーによって情報の粒度が違い状況が把握しにくかった スプリントの全体像がわからず検査がしにくかった 改善後:スプリントに積まれたバックログアイテムをベースにして各自昨日やったこと・今日やること・困っていることの共有 スプリント全体のタスクを見渡せるので臨機応変に動きやすくなった バックログ上に開発時のメモやマーケターとのやりとりなどが記載されているので内容の把握がしやすくなった レトロスペクティブ レトロスペクティブはチームでのふりかえり自体はできていたので、そこからさらに具体的なアクションへの落とし込みができればもっと良いものになると感じていました。 改善前:毎週のスプリントでの出来事をKPTA法でふりかえり その場その場でのふりかえりはできていたが、スクラムが改善していっている実感は薄かった アクションアイテムの決定にあまり注力できていなかった 改善後:毎回テーマを決め様々な手法を使ってふりかえりを行い、毎回アクションアイテムを議論する時間を設けた テーマに応じて異なる手法(5つのなぜ、YWT、小さなカイゼンアイデア、etc)を使って効果的なふりかえりを実施(マンネリ化の防止も) miro を使って自分が気になった・共感した付箋に対してスタンプをつけ、関心が集まった内容について議論 2,3個に絞ったほうが次スプリントのアクションとして実践しやすく毎週続けやすかった 多くのメンバーの関心がある効果的なアクションが決められるため、チームとして改善を進めていると実感できた レトロスペクティブ自体のふりかえりも定期的に行い、より有意義な時間となるよう意見を出し合っている リファインメント・プランニング(マーケターの参加) リファインメント・プランニングはこれまで開発チームだけで行なっていましたが、マーケターとも話し合い、スクラムに本格的に参加してもらうよう体制を変えていきました。 改善前:マーケターはスクラムに未参加 マーケターが開発チームの状況を把握できる場がなかった スプリントに積むタスクの意思決定を開発が行っており認識相違が発生していた 改善後:毎週のリファインメントとプランニングに入ってもらう 透明性が格段に上がったことで認識相違が減った リファインメントの際に確認作業もその場で効率的に済ませられるようになった 環境改善タスクの必要性も理解してもらえて負債の解消タスクもスプリントに積みやすくなった コミュニケーションの改善 開発チームとマーケターで1on1ミーティングの実施 こちらは人材紹介開発グループのグループ長である @kenjiszk さんの提案で、担当領域ごとに開発チームのメンバーとマーケターのリーダーで主に情報共有を目的とした定期的な1on1ミーティングを実施するようになりました。 改善前:タスク依頼の共有を行う定例でしか話す場がなかった マーケターの業務に関する情報を知る場がほとんどなかった マーケターが小さな相談をしたい時にコミュニケーションする場がなかった 改善後:週次で1on1ミーティングを実施することでコミュニケーション活性化 お互いの状況を把握できて相談しやすくなった この1on1ミーティングの実施が開発チーム・マーケター間の関係性を強めるきっかけになった オフラインイベントの実施 こちらは改善のアクションという名目で行ったわけではないのですが、様々な改善を行ってきた結果、開発チームとマーケターで本社でのオフラインイベントを実施することができました! 【イベントの詳細】 チーム対抗NASAゲーム(チームで合意形成を行うコンセンサスゲームの一種) この後のふりかえりをチームで行うため、先にチームの雰囲気を良くする意図 話したことがない人とも話すためお互いの自己紹介も兼ねていた 開発チーム・マーケターの体制についてふりかえり チームごとにふりかえりを行い、アクションアイテムを出し合う それぞれのチームから出たアクションアイテムを共有し、特に関心が集まった内容から開発チーム・マーケター合同のネクストアクションを決定 「アジャイルの各イベントをマーケターにもっと浸透させる」「開発チームに対して事業状況の共有と施策のふりかえりを行う」等のお互いに理解を進めるための良いアクションアイテムが決定 最後にお世話になった人たちにmiroで感謝を伝えあう 【イベントを終えて】 「すごく楽しかったです!」「とても良い取り組みでした!」と色々な人に言っていただけて嬉しかったです。 企画から当日の進行まで私が責任を持って任せて頂いたため、本番前の一週間はうまくいくか心配で寝つきが悪かったですが頑張ってよかったです。 個人的にはこのイベントを実施したことでマーケターのリーダー以外のメンバーの人たちとも話しやすくなったと感じたので何よりでした。 最後に 最後までご覧いただきありがとうございました。入社時に主にスクラムに関して私が感じた課題とそれに対するアクションをご紹介させていただきました。 以前より開発チームとマーケターの距離が縮まったものの、タスクの管理方法やより効率的なミーティングの設計など課題は多く残っています。 それらの課題を改善していくと同時に、今後サービスをより成長させるためにマーケターと協力しながら何ができるのかを考え実践していこうと思います。
アバター
こんにちは!カイゴジョブの開発をしております @katorie です。普段はRuby on Railsを使ってプロダクトの改善や新機能開発に取り組んでいます。 すでにこのブログでは弊社の学生支援によってRubyKaigi 2025に参加した学生の皆さんのレポートが公開されておりますが、ご覧いただけましたでしょうか? 私からは、子連れで参加したRubyKaigi 2025についてお伝えしたい思います。あくまで私個人の感想とともに一例としてのご紹介になりますが、RubyKaigi に参加するスタイルのひとつとしてどなたかの参考になることを願っています。 なぜ子どもを連れてRubyKaigiに参加するか 今回RubyKaigiに子どもを連れて参加したのには、いくつか理由があります。 まず単純に、「行きたい」という気持ちがありました。RubyKaigiは、Rubyに関わる開発者にとって年に一度のお祭りのような存在。毎年楽しみにしているイベントのひとつです。とはいえ、家庭の事情や育児の状況によって「今年は無理かな…」と参加を諦めてしまいそうになる瞬間もあります。 でも、「子どもがいるから行けない」のではなく、「子どもと一緒に行く」という選択肢があってもいいのではないでしょうか。 幸い、RubyKaigiでは託児所の提供など子連れ参加へのサポートが整っています。それを活用すれば、セッションを楽しみながらも、子どもに無理のない形で参加できるかもしれない。そう思って、思い切って申し込むことにしました。 ちなみに、弊社ではRubyKaigiへの参加は出張の扱いになります。私の出張に子どもを帯同するということになり、私の旅費と宿泊費は会社負担になります。会社からは子どもを帯同することで勤務時間の確保が可能かという点の確認がありましたので、託児所の存在が決め手になりました。 もうひとつの理由は、自分の尊敬する人たち、仕事仲間を子どもに少しでも見せてみたいという気持ちです。私は普段、「カイゴジョブ」の開発に携わっています。日々PCに向かっている姿を見ている子どもたちに、「お母さんはこんな仲間と一緒に働いてるんだよ」と伝える機会があったら素敵だなと思いました。 子どもを連れてRubyKaigiに参加するのは、控えめに言って最高である まず、子どもを連れてRubyKaigiに参加することは、控えめにいって最高です!いきなり個人的な感想全開ですが、具体的に最高と感じた瞬間を整理してみたいと思います。 まずありがたいことに、RubyKaigi 2025ではNursery SponsorとしてSTORES社が運営する託児所が存在します。事前登録すれば、会場内の専用スペースで子どもを預かってもらえるため、安心してセッションに集中することができます。もちろん、日々の子どもの体調や様子には常に気を配りながらにはなりますが、プロの保育士さんや親切なSTORES社のスタッフの皆さんがあたたかく迎えてくださったので、安心して預けることができました。親としても、エンジニアとしても、どちらも大切にできる環境が整っていると感じました。 また、私が仕事で関わっている人たちや尊敬するプログラマーの皆さんと直接会い、子どもに紹介できたことも貴重な経験でした。たとえば、2日目のLightning Talks(LT)で「Road to RubyKaigi: Making Tinny Chiptunes with Ruby」というタイトルで発表されていた @makicamel さんには、LTで披露されていたゲームを子どもに体験させてくださいました。目の前にあるものを作っている人と触れ合うという体験は、子どもにとってもとても印象深かったようです。 後日、また思い出して「あのゲームかわいかったな、あれ作ったのすごいな」と思い出していました。 私自身が楽しんでいる姿を子どもに見せられるというのも、思った以上に意味があることでした。子どもは大人の背中をよく見ています。いつもと違う場所で、刺激を受けながら楽しむ親の姿は、きっと何かしらポジティブな印象として残るのではないかと思います。 さらに、託児所で子どもたちが普段の生活圏とは違う友達と出会い、新しい環境で過ごすという体験も大きなメリットでした。親子ともに「非日常」を共有できるこの時間は、ちょっとした旅行以上に心に残るものでした。 3日目の最後に来年の会場が函館であることがわかってからは、初めて聞く地名を地図で探したり、託児所で一緒だったお友達とまた会えるかなと期待したり、すっかり来年のRubyKaigiを心待ちにしています。 子連れ参加に向けた準備 もう少し具体的なTipsもご紹介したいと思います。子連れでカンファレンスに参加するとなると、やはり事前の準備は必要です。私も「どうなるかな?」と不安を抱えながらの参加でしたが、いくつか工夫をすることで、当日は比較的スムーズに過ごすことができました。 まず、託児所の申し込みは最優先事項です。RubyKaigiにおける託児所の設置は初回が2016年となっており、コロナ禍を除いてはほぼ毎回用意されています。チケットの購入時点でその存在を知ることができるようになっています。 宿泊先については、子どもと過ごしやすいかどうかが重要なポイントになります。例えば大浴場付きだったり、部屋が広めだったり、近くにコンビニやコインランドリーがあると何かと助かります。子どもが小さい場合は、ベビーベッドや子ども用の備品が借りられるかどうかも要チェックです。これは過去の私のエピソードですが、託児所に預けるためにはお弁当持参だったので、宿泊先にキッチンがついていることが条件になったこともありました(今ではコンビニで買ったものが食べられるようになったのでキッチンは必要条件ではなくなりました)。今回、私は道後温泉エリアのホテルに宿泊しましたが、歩いて外湯を巡ることができる環境だったので、毎晩子どもたちと温泉を楽しんでいました。 荷物については、移動中の荷物を少なくするために事前にホテルに3泊分の着替えを送っていました。移動中はお気に入りのおやつやタブレット、ヘッドフォンなど、子どもが落ち着いて過ごせるアイテムはマストです。子どもの月齢にもよりますが、子どもが座ることができるキャリーケースは大活躍しています。 もし可能であれば、家族のサポートも得られるとよいでしょう。今回私はひとりで子ども2人を連れて行きましたが、現地では弟家族と合流して過ごしました。他のご家庭の様子をうかがうと、パートナーやご両親も一緒に滞在されている方が多いようでした。 最後に、心構えとして「全部のセッションに参加できなくてもOK」という気持ちを持っておくと、当日の心理的負荷がだいぶ下がります。見たいセッションを事前にピックアップしておきつつ、場合によっては録画やスライドで後から追うことも良しとして、無理せず楽しむことを優先しました。 実際の参加レポート 会場に到着するまでは「本当に子どもと一緒で大丈夫かな……」という不安も正直ありました。でも、いざ始まってみると、そんな心配はすぐに吹き飛びました。 託児スペースはセッション会場とは別の階に設けられていて、落ち着いた雰囲気の中で子どもたちが過ごせるようになっていました。スタッフの方々も慣れていて、子どもが安心して過ごせる空気を作ってくれていたのが印象的です。専用のSlackチャンネルを用意していただいていて、楽しそうに遊んでいる様子が写真で共有されていました。 イベント中は、子どもを連れて会場内を移動する場面もありましたが、周囲の参加者やスタッフの方々がとてもフレンドリーに声をかけてくださり、肩の力が抜けました。RubyKaigiらしい、オープンで温かい雰囲気に何度も助けられました。 2日目の夜には、STORES社が主催するSTORES Cafeにも参加しました。ノンアルコールのカジュアルな雰囲気で、子連れの参加者も多く、とてもありがたい存在でした。子どもも少し遅い時間ではありましたが、楽しく過ごすことができ、ゆるやかに交流の輪が広がる時間を楽しめました。 参考までに、3日目の我が家のタイムラインを書き出してみます。 託児所では公園での外遊びに連れて行ってくださったり、紙コップアートのワークショップがあったりと子どもたちが楽しめる工夫がたくさんありました。 まとめとアドバイス RubyKaigi 2025に子どもと一緒に参加してみて、本当に良かったと思っています。 準備はそれなりに必要でしたし、当日もイレギュラーなことが起きないわけではありません。でも、「カンファレンスに行くか、子どもと過ごすか」の二択ではなく、「子どもと一緒に行く」という選択肢があることを、あらためて実感しました。 もちろん、すべての家庭やタイミングで実現できるわけではないと思いますが、もし少しでも「行ってみたいな」「子どもを連れても大丈夫かな」と考えている方がいたら、ぜひチャレンジしてみてほしいです。 ここに、私なりの子連れ参加Tipsをいくつかまとめておきます。 託児所の事前申し込みは最優先 ホテル選びは立地と子ども向け設備を重視 荷物は事前に送る、手荷物にはお気に入りグッズを セッションは無理せず、気になるものを数本ピックアップ 子どものペースを最優先に、余白あるスケジュールを 子育て中でも技術コミュニティとつながり続けたい、そんな思いを叶えてくれる場として、RubyKaigiはとてもやさしい場所でした。 子ども帯同での出張として快く送り出してくださったチームの皆さんにもとても感謝しています。 来年も、また家族で参加できたらいいなと思っています。 株式会社エス・エム・エスでは、子育てしながらお仕事する環境も整っています!普段どんなふうに過ごしているか等、具体的なお話が気になった方はカジュアル面談でカジュアルに聞いてくださいね。
アバター
エス・エム・エスで全社 SRE というロールで活動している Security Hub 芸人の山口( @yamaguchi_tk )です。 おすすめのAWSサービスは営業です(いつもお世話になっています)。 1. はじめに 1.1 背景 株式会社エス・エム・エスでは、全社横断の SRE チームが AWS Organizations 配下で 130 以上の AWS アカウントと、200 名を超える開発者の認証と認可を管理しています。AWS IAM Identity Center の導入と Terraform による IaC 化、CI/CD による自動デプロイは整っていますが、ユーザー追加や権限変更のリクエストが積み重なり、運用負荷は増加する一方でした。 1.2 目指す姿 私たちが狙ったゴールはシンプルです。 運用負荷の軽減 設定ファイルベースで権限管理し CI/CD で自動化 開発チームへの安全な委譲 直感的に編集できるテキストファイルで「自分が担当しているアカウントの権限付与は自分たちで管理」 以下では、これを実現するために採ったアプローチと具体的なコードをご紹介します。 TL;DR: 「ヒトに権限を割り当てる」変更はテキストファイルを直すだけ。あとは CI/CD が全部やってくれる、そんな世界を Terraform とAWS IAM Identity Center で実現しました。 2. AWS IAM Identity Center の基本 2.1 機能概要 シングルサインオン (SSO) 一度の認証で複数アカウントにアクセス Azure AD や Okta など外部 IdP との連携 マルチアカウント管理 全てアカウントへのアクセス制御を統合 許可セット IAMポリシーをテンプレート化して再利用 ユーザー/グループ単位で割り当て 2.2 主要な概念 ユーザー Identity Center で管理される個々の利用者 メールアドレスを一意の識別子として使用 グループ ユーザーの集合を管理する単位 許可セット ポリシーとロールのテンプレート アカウント割り当て アクセス制御の基本単位 ユーザー/グループとアカウントの紐付け 許可セットの適用 3. Terraform での実装 3.1 標準的な実装例 標準的な Terraform による実装では、以下のようなコードを記述します。 # ユーザーの定義 resource "aws_identitystore_user" "example" { identity_store_id = aws_ssoadmin_instances.example[0].identity_store_id display_name = "Example User" user_name = "user@example.com" emails { value = "user@example.com" } } # グループの定義 resource "aws_identitystore_group" "example" { identity_store_id = aws_ssoadmin_instances.example[0].identity_store_id display_name = "Example Group" description = "Example group for testing" } # ユーザーをグループに割り当て resource "aws_identitystore_group_membership" "example" { identity_store_id = aws_ssoadmin_instances.example[0].identity_store_id group_id = aws_identitystore_group.example.group_id member_id = aws_identitystore_user.example.user_id } # 許可セットの定義 resource "aws_ssoadmin_permission_set" "example" { name = "ExamplePermissionSet" description = "Example permission set" instance_arn = aws_ssoadmin_instances.example[0].arn session_duration = "PT1H" } # 許可セットへポリシーのアタッチ resource "aws_ssoadmin_managed_policy_attachment" "example" { instance_arn = aws_ssoadmin_instances.example[0].arn permission_set_arn = aws_ssoadmin_permission_set.example.arn managed_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" } # ユーザーをアカウントに割り当て resource "aws_ssoadmin_account_assignment" "example" { instance_arn = aws_ssoadmin_instances.example[0].arn permission_set_arn = aws_ssoadmin_permission_set.example.arn target_id = "123456789012" target_type = "AWS_ACCOUNT" principal_id = aws_identitystore_user.example.user_id principal_type = "USER" } 標準的な実装では、各リソースを個別に定義し、リソース間の依存関係を明示的に記述します。 例えば、グループメンバーシップの定義では、ユーザーとグループの ID を直接参照(リソース指定することも可能)する必要があります。 3.2 標準的な実装例での Terraform Plan 例 標準的な実装例での Terraform Plan 例を以下に示します。 # aws_identitystore_user.example will be created + resource "aws_identitystore_user" "example" { + display_name = "Example User" + identity_store_id = "d-1234567890" + user_id = (known after apply) + user_name = "user@example.com" + emails { + value = "user@example.com" } } # aws_identitystore_group_membership.example will be created + resource "aws_identitystore_group_membership" "example" { + group_id = "1234567890abcdef" + identity_store_id = "d-1234567890" + member_id = (known after apply) } # aws_ssoadmin_account_assignment.example will be created + resource "aws_ssoadmin_account_assignment" "example" { + instance_arn = "arn:aws:sso:::instance/ssoins-1234567890abcdef" + permission_set_arn = "arn:aws:sso:::permissionSet/ssoins-1234567890abcdef/ps-1234567890abcdef" + principal_id = (known after apply) + principal_type = "USER" + target_id = "123456789012" + target_type = "AWS_ACCOUNT" } 許可セットを付与する対象のユーザーが内部 ID( ssoins-1234567890abcdef など)で表示されています。 3.3 標準的な実装における課題 標準的な実装では、以下のような課題があります。 コードが複雑になる 多数のリソース定義が必要となり、コード量が膨大になる リソース間の依存関係の管理が複雑 変更の影響範囲の把握が困難 レビューの困難さ 内部 ID による表示のため、Terraform Plan で変更内容を把握することが難しい 3.4 課題を解決するために採用したアプローチ これらの課題に対処するために、私たちは三つの方針に沿って改善を進めました。 コード量の削減 Assignment 等の実装をテキストファイル化する レビューを楽に Terraform Plan にメールアドレス、グループ名、許可セット名を表示する 開発チームに安全に委譲できるように 安全に変更できるように AWS アカウント単位で委譲できる仕組みにする ディレクトリ、ファイル名だけで目的が伝わる構造にする 4. 具体的な実装 4.1 ディレクトリ構造 terraform/ ├── user/ # ユーザー管理 │ ├── user.txt # ユーザーリスト(メールアドレス) │ └── dummy.tf ├── membership/ # グループメンバーシップ │ ├── XXX_Developers.txt # 開発者グループ │ ├── XXX_SREs.txt # SREグループ │ ├── YYY_Developers.txt # 開発者グループ │ ├── YYY_SREs.txt # SREグループ │ └── dummy.tf ├── assignment/ # アクセス権限の割り当て │ ├── 12345678/ # AWSアカウントID │ │ ├── AdministratorAccess_GROUP.txt │ │ ├── PowerUserAccess_GROUP.txt │ │ ├── AdministratorAccess_USER.txt │ │ ├── PowerUserAccess_USER.txt │ │ └── dummy.tf │ ├── 23456789/ │ └── ... ├── su/ # symlinkによる組織構造 │ ├── 医療キャリア/ # 開発者グループ │ │ ├── prd -> ../../assignment/12345678 │ │ ├── stg -> ../../assignment/23456789 │ │ └── dev └── others/ # Terraformの実装コード ├── variables.tf # 変数定義 ├── assignmeents.tf # assignmentの実装コード ├── assignmeents_dummy.tf # dummy.tfを読み込むための実装コード ├── memberships.tf # group membershipの実装コード ├── permissionsets.tf # permission setの実装コード ├── users.tf # userの定義コード └── groups.tf # Groupの実装コード 4.2 設定ファイルの実装例 ユーザー管理(user/user.txt) Identiy Center に登録するユーザーのメールアドレスを記載します。 user1@example.com user2@example.com グループ管理(membership/XXX_Developers.txt, membership/XXX_SREs.txt) {グループ名}.txt という形式でファイルを作成します。 Group に所属させるユーザーのメールアドレスのメールアカウント部分(@より左側)を記載します。 user1 user2 アクセス権限・グループ(assignment/12345678/AdministratorAccess_GROUP.txt) {許可セット名}_GROUP.txt という形式でファイルを作成します。 ディレクトリ名の AWS アカウント ID で、テキストファイル名のアンダースコア `_` の左側に記載の許可セットを付与する Group 名を記載します。 XXX_SREs アクセス権限・ユーザー(assignment/12345678/AdministratorAccess_USER.txt) {許可セット名}_USER.txt という形式でファイルを作成します。 ディレクトリ名の AWS アカウント ID で、テキストファイル名のアンダースコア `_` の左側に記載の許可セットを付与する ユーザーのメールアドレスのメールアカウント部分(@より左側)を記載します。 user1 user2 ※ 弊社の環境では、Identity Center への認証は外部 IdP による SSO からのアクセスのみに絞っているので、@より右側のドメイン名は全ユーザー共通です。 4.4 実装コード user 定義(others/users.tf) ################################################################################ # User ################################################################################ resource "aws_identitystore_user" "this" { for_each = local.users display_name = each.value identity_store_id = "d-abc1234567" user_name = each.value emails { primary = true type = "work" value = each.value } name { family_name = " " given_name = " " } } ################################################################################ # Users ################################################################################ locals { user_file = "../user/user.txt" # ファイルが存在すれば読み込む、なければ空リスト emails = (can(fileexists(local.user_file)) && fileexists(local.user_file) ? split("\n", trimspace(file(local.user_file))) : []) users = { for email in local.emails : regex("(^[^@]+)", email)[0] => email } } ################################################################################ # dummy module ################################################################################ module "dummy_user" { source = "../user" } Group 定義(others/groups.tf) ################################################################################ # Groups ################################################################################ locals { groups = [ "XXX_SREs", "XXX_Developers", "YYY_SREs", "YYY_Developers", ] group_map = { for group in local.groups : group => { group_name = group } } } resource "aws_identitystore_group" "this" { for_each = local.group_map display_name = each.value.group_name identity_store_id = "d-abc123456" } assignment 定義(others/assignments.tf) locals { merged_targets = concat(local.assignment_target_users, local.assignment_target_groups) # assignments_targets の各要素に対して処理 # { # file_name = "PowerUserAccess_USER.txt" # permission_set_arn = "arn:aws:sso:::permissionSet/..." # principal_type = "USER" # # file_exists = true/false # raw_user_names = [...] # user_ids_map = { "alice" = "uuid1", "bob" = "uuid2" } # } # のような構造を作る flatten_targets = flatten([ for account in local.assignment_target_aws_accounts : [ for t in local.merged_targets : { file_path = "${local.assignment_file_path}/${account}/${t.file_name}" file_name = t.file_name account = account permission_set_arn = t.permission_set_arn principal_type = t.principal_type } ] ]) assignment_targets_expanded = [ for t in local.flatten_targets : { file_name = t.file_name account = t.account resourcename_prefix = trimsuffix(t.file_name, ".txt") permission_set_arn = t.permission_set_arn principal_type = t.principal_type file_path = t.file_path file_exists = can(fileexists(t.file_path)) && fileexists(t.file_path) # ファイルが存在すれば読み込む、なければ空リスト raw_user_names = (can(fileexists(t.file_path)) && fileexists(t.file_path) ? split("\n", trimspace(file(t.file_path))) : []) # TXTファイルが空の場合を考慮 # 空文字列""の場合はLISTから外す user_names = [ for name in can(fileexists(t.file_path)) && fileexists(t.file_path) ? split("\n", trimspace(file(t.file_path))) : [] : name if name != "" ] } ] } ################################### # assignment_targets_expanded をフラットに合体 ################################### # 例: { # "PowerUserAccess_USER.txt-alice" = { user_id="xxx", permission_set_arn="yyy", principal_type="USER" } # "PowerUserAccess_USER.txt-bob" = { user_id="xxx", permission_set_arn="yyy", principal_type="USER" } # "AdministratorAccess_USER.txt-charlie" = { ... } # } locals { combined_assignment_users = merge([ # assignment_targets_expanded の各要素 t に対して… for t in local.assignment_targets_expanded : { # さらに t.user_ids_map の各 entry (user_name, user_id) について… for user_name in t.user_names : # キーを "<awsaccount_id>_<file_name>_<user_name>"、値をオブジェクトにする "${t.account}_${t.resourcename_prefix}_${user_name}" => { user_name = user_name account = t.account permission_set_arn = t.permission_set_arn principal_type = t.principal_type } } ]...) } ################################### # for_each で一括作成 ################################### # combined_assignments には「(ファイル名)-(ユーザー名)」がキーになっている resource "aws_ssoadmin_account_assignment" "this" { for_each = local.combined_assignment_users instance_arn = local.instance_arn target_id = each.value.account target_type = "AWS_ACCOUNT" principal_id = each.value.principal_type == "USER" ? aws_identitystore_user.this[each.value.user_name].user_id : aws_identitystore_group.this[each.value.user_name].group_id principal_type = each.value.principal_type permission_set_arn = each.value.permission_set_arn } membership 定義(others/memberships.tf) locals { # memberships_targets の各要素に対して処理 # { # file_name = "SREs.txt" # group_id = "..." # # file_exists = true/false # raw_user_names = [...] # user_ids_map = { "alice" = "uuid1", "bob" = "uuid2" } # } # のような構造を作る memberships_targets_expanded = [ for t in local.memberships_targets : { file_name = t.file_name resourcename_prefix = trimsuffix(t.file_name, ".txt") group_name = trimsuffix(t.file_name, ".txt") file_path = "${local.membership_file_path}/${t.file_name}" file_exists = can(fileexists("${local.membership_file_path}/${t.file_name}")) && fileexists("${local.membership_file_path}/${t.file_name}") # ファイルが存在すれば読み込む、なければ空リスト raw_user_names = (can(fileexists("${local.membership_file_path}/${t.file_name}")) && fileexists("${local.membership_file_path}/${t.file_name}") ? split("\n", trimspace(file("${local.membership_file_path}/${t.file_name}"))) : []) # TXTファイルが空の場合を考慮 # 空文字列""の場合はLISTから外す user_names = [ for name in can(fileexists("${local.membership_file_path}/${t.file_name}")) && fileexists("${local.membership_file_path}/${t.file_name}") ? split("\n", trimspace(file("${local.membership_file_path}/${t.file_name}"))) : [] : name if name != "" ] } ] } ################################### # membership_targets_expanded をフラットに合体 ################################### # 例: { # "SREs-alice" = { group_id="xxx", user_id="xxx" } # "SREs-bob" = { group_id="xxx",user_id="xxx" } # "SREs-charlie" = { ... } # } locals { combined_memberships = merge([ # assignment_targets_expanded の各要素 t に対して… for t in local.memberships_targets_expanded : { # さらに t.user_ids_map の各 entry (user_name, user_id) について… for user_name in t.user_names : # キーを "<file_name>_<user_name>"、値をオブジェクトにする "${t.resourcename_prefix}_${user_name}" => { group_name = t.group_name user_name = user_name } } ]...) } ################################### # for_each で一括作成 ################################### # combined_memberships には「(ファイル名)_(ユーザー名)」がキーになっている resource "aws_identitystore_group_membership" "this" { for_each = local.combined_memberships identity_store_id = "d-95671a55c2" group_id = aws_identitystore_group.this[each.value.group_name].group_id member_id = aws_identitystore_user.this[each.value.user_name].user_id } ################################################################################ # dummy module ################################################################################ module "dummy_menbership" { source = "../membership" } variables 定義(others/variables.tf) locals { instance_arn = tolist(data.aws_ssoadmin_instances.instance.arns)[0] assignment_file_path = "../assignment" # assignment以下のフォルダを列挙 assignment_target_aws_accounts = distinct([ for file in fileset(local.assignment_file_path, "*/*.txt") : dirname(file) ]) membership_file_path = "../membership" } locals { # assignments_targets の定義 assignment_target_groups = [ { file_name = "AdministratorAccess_GROUP.txt" permission_set_arn = aws_ssoadmin_permission_set.AdministratorAccess.arn principal_type = "GROUP" }, { file_name = "DeveloperAccess_GROUP.txt" permission_set_arn = aws_ssoadmin_permission_set.DeveloperAccess.arn principal_type = "GROUP" }, ] assignment_target_users = [ { file_name = "AdministratorAccess_USER.txt" permission_set_arn = aws_ssoadmin_permission_set.AdministratorAccess.arn principal_type = "USER" }, { file_name = "Developer_USER.txt" permission_set_arn = aws_ssoadmin_permission_set.Developer.arn principal_type = "USER" }, ] } locals { memberships_targets = [ { file_name = "XXX_SREs.txt" }, { file_name = "XXX_Developers.txt" }, { file_name = "YYY_SREs.txt" }, { file_name = "YYY_Developers.txt" }, ] } dummy.tf 読み込み(others/assignments_dummy.tf) module "dummy_12345678" { source = "../assignment/12345678" } module "dummy_23456789" { source = "../assignment/23456789" } ... 4.5 実装のポイント 設定ファイルの読み込みは、Terraform の file() 関数を使用して実装しています。ファイルの内容を行ごとに分割し、 trimspace() で空白を除去することで、クリーンなデータを取得します。空行は if user != "" の条件で除外し、有効なデータのみを処理対象としています。 リソースの生成は、 for_each を使用して動的に行います。ネストされたリストは flatten() で平坦化し、一意のキーを生成することで重複を防止しています。これにより、設定ファイルの変更が効率的にリソースの更新に反映されます。 エラーハンドリングは、ファイルの存在確認から始まります。存在しないファイルに対しては file() 関数がエラーを返し、不正な形式のデータは split() や trimspace() で適切に処理されます。また、存在しないユーザーやグループへの参照は、Terraform の実行時にエラーとして検出されます。 今回は tfaction を利用することを前提としているため、設定ファイルを置いているディレクトリに dummy.tf を配置し、ディレクトリ自体を module として扱っています。 tfaction-root.yaml に以下の設定を追加することで module 側で変更があった場合(=設定ファイルに変更があった場合)に Terraform Plan が実行されるようになります。 update_local_path_module_caller: enabled: true 4.6 実装したコードでの Terraform Plan 表示 # aws_identitystore_group_membership.this["XXX-SREs_user1"] will be created + resource "aws_identitystore_group_membership" "this" { + group_id = "abc12345-1234-1234-1234-abc123456789" + id = (known after apply) + identity_store_id = "d-1234567890" + member_id = (known after apply) + membership_id = (known after apply) } # aws_ssoadmin_account_assignment.this["123456789012_PowerUserAccess_USER_user1"] will be created + resource "aws_ssoadmin_account_assignment" "this" { + id = (known after apply) + instance_arn = "arn:aws:sso:::instance/ssoins-1234567890abcdef" + permission_set_arn = "arn:aws:sso:::permissionSet/ssoins-1234567890abcdef/ps-1234567890abcdef" + principal_id = (known after apply) + principal_type = "USER" + target_id = "123456789012" + target_type = "AWS_ACCOUNT" } # aws_identitystore_user.this["user1"] will be created + resource "aws_identitystore_user" "this" { + display_name = "user1@example.com" + external_ids = (known after apply) + id = (known after apply) + identity_store_id = "d-1234567890" + user_id = (known after apply) + user_name = "user1@example.com" + emails { + primary = true + type = "work" + value = "user1@example.com" } + name { + family_name = " " + given_name = " " } } 4.7 開発チームへの委譲 ここまで実装できると、AWS アカウント単位に作成したディレクトリ単位や、XXX_GROUP.txt 単位で CODEOWNER を開発チームに設定することで、開発チームが管理しているグループへのメンバー追加や AWS アカウントへの権限付与について、開発チームが自律的な対応が可能になります。 4.8 課題の解決 コードが複雑になる 日常的に変更する必要のあるコードをシンプルにすることで解決しました。 具体的には、ユーザーの追加、グループへのユーザー追加、ユーザー・グループへの権限付与について、プレーンなテキストファイルによる設定ファイル方式を採用することで、コードをシンプルに保つことができるようになりました。 レビューの困難さ 内部 ID ではなく、人間が見て変更内容がわかるような Plan 表示を行うことで解決しました。 具体的には、「誰に」「何の権限を」「どの AWS アカウントに」付与するのかを人間が見てわかるような Terraform Plan 表示を実現することで、Plan 表示を確認するだけで変更内容が把握できるようになりました。 4.9 今回の実装が実現できた要因 今回の実装が実現できた要因として、現状の運用規模と運用スタイルがあると思います。 弊社の規模として、前述の通りAWS アカウント数が 130 以上、開発者数が 200 名以上です。それ以外の Identity Center での管理単位としては、グループ数が数十程度、許可セット数が10個程度で運用しています。 許可セットはセキュリティの最小権限の原則を考慮すると、AWS アカウント、アプリケーションのアーキテクチャ、開発者の属性、運用方法に応じた細かい粒度での許可設定が求められますが、弊社では、全社 SRE チームが全社横断で管理するため、管理負担とのバランスを取りつつ最小権限ではなく広めに権限を付与するような許可セットで運用しています。 この運用方法と規模感だから、プレーンテキストファイルによる設定、モノレポ管理、CI/CDでの自動化の実装と運用ができていると言えます。 5. まとめ 運用の効率化 1行1エントリのプレーンなテキストファイルでのシンプルな設定により、簡単に権限付与・削除が出来るようになりました。 また、Git の履歴を追うだけで権限付与の履歴も一目瞭然になりました。 for_each / flatten() による 動的リソース生成 を実装することでコード量を大幅削減できました。 レビュー体験の向上 Plan 出力にメールアドレス、ユーザー名、グループ名、許可セット名がそのまま表示されることで、「誰に」「何の権限を」「どの AWS アカウントに」付与するかが、Terraform Plan を確認するだけで可能になりました。 目的を持ったディレクトリ構造のため、ファイル差分で変更の意図が伝わるようになりました。 開発チームへの安全な委譲 プレーンなテキストファイルの編集だけで権限の付与が完了します。 AWS アカウント ID 毎のディレクトリ構造で、環境と権限の関係が直感的になりました。 また、symlink で日本語名称を付けたディレクトリ構造を作成することで、対象とするAWS アカウント IDを直感的に探すことが可能になりました。 これからのチャレンジ 生成 AI を活用した Issue から自動で PR を作成する等による AI OPS にチャレンジしていきます。(注釈:過去に Amazon Q Developer を利用したチャレンジは失敗しています→ https://speakerdeck.com/yamaguchitk333/codecatalyst-in-action-automating-pr-creation-for-route-53-and-iam-identity-center-management ) 許可セットの単位がまだ荒いので、その粒度を細かくするか ABAC にすることでセキュリティの強化を行います。
アバター
こんにちは、 Retasusan です。 普段は大学に通いながら、京都のスタートアップでRuby on Railsを使ったアプリケーションを書いていますが、「Rubyエンジニア」と胸を張って名乗れるほどRubyについて詳しいかと言われると正直まだまだです…。 そんな自分が、日本最大級のRubyカンファレンス RubyKaigi 2025 に初参加してきたので、現地の空気感や交流の様子を中心にまとめてみました! RubyKaigiとの出会い 最初にRubyKaigiを知ったのは、 Kyoto Tech Talk というイベントにお邪魔した時のことでした。学生支援があるという話を聞き、紆余曲折ありつつエス・エム・エスに応募させていただき、書類選考とリモートでの面接の後に採択していただきました! ありがたいことに松山への交通手段とRubyKaigiのチケットを確保できました。本当にありがとうございます! 事前準備 正直なところ、「RubyKaigiって何をするの?」というレベルからのスタートでした。 せめて登壇セクションの内容くらい理解しておかないといけないと思い、全く時間が足りませんでしたが、インターネットの内海に潜っては、時に溺れながらRubyについて調べていきました。 そして、今回の学生支援にはOfficial Partyなどのイベントは含まれていなかったため、各イベントをRubyKaigiのeventページと睨めっこしながらconnpass経由で予約していきました。 事前の予定は以下の通りです。ご覧の通り具体的な予定は全くないのですが、まぁなんとかなるだろうという気持ちで当日を迎えました。また、Day0の飛行機をうっかり早朝に予約してしまったため、前日をカラオケで過ごすことで搭乗に成功しました。 日付 4/14(月) Day-1 深夜のカラオケにて夜を明かす 4/15(火) Day0 松山観光(松山に前乗り) 4/16(水) Day1 4/17(木) Day2 4/18(金) Day3 最終日 4/19(土) Day4 松山観光(京都に帰還) Day0 この日は、ほとんど観光しかしていません。松山空港に着くとRubyKaigiのバナーがあったのでテンションが上がりました。 来ました #rubykaigi pic.twitter.com/gmvSGMoGcm — Retasusan (@retasusan_510) 2025年4月15日 友人とPre-Checkinのために会場に行きましたが、時間を間違えていたため出直しました。 Pre-checkin失敗(時間を読み間違えていた…) — Retasusan (@retasusan_510) 2025年4月15日 まだスタッフさん以外いない会場 その後は、松山城や道後温泉に行った後で、 SmartHRさんのDrinkup に参加しました。 まだRubyKaigiの雰囲気に馴染めておらず、あまり交流できませんでした。 Day1 この日聞いたセッション Ruby Taught Me About Encoding Under the Hood Introducing Type Guard to Steep State of Namespace TRICK 2025: Episode I ima1zumiさんの文字コードの話は印象深かったです。途中からDevanagari文字の話が出てきていました。 本来「クタァ」と繋がらないといけない部分が「ク」と「タァ」に分割されているというお話がありました。それを聞いて、Unicode対応にはDevanagari文字に精通しないといけないのかと戦々恐々としました。 ima1zumiさんのKeynoteのスライド資料は公開されているのでよければそちらをご覧ください。 This is my RubyKaigi keynote presentation. Thank you! https://t.co/Ld7X6QNyMf — ima1zumi (@ima1zumi) 2025年4月16日 また、Takeshi KOMIYAさんのSteepでの型ガードの話はかなり興味深かったです。正直、RBSを使用したことがなかったのですが、元々動的型付け言語であるRubyに型をつけることは、かなり難しさがあるのだろうなと思いました。 この時点では未来の話になるのですが、実は3日目の さくらインターネットさんでの打ち上げ でお話をする機会がございました。 楽しかったです! #rubyfriends pic.twitter.com/kMUqrAtGzo — Retasusan (@retasusan_510) 2025年4月18日 お昼はPixivさんの学生支援の方とエス・エム・エスの支援学生でお昼の交流会がありました。実は遅刻するほどCookpadさんの方との話が盛り上がってしまいました…!振り返ると、RubyKaigiでは意識して時計を見ないと時間を忘れて話してしまいがちでした。次回以降のRubyKaigiではこの反省を活かしたいと思います! 鯛めし。おいしかったです。 午後からは、tagomorisさんのNamespaceについてのセッションをお聞きしました。 この日最後のセッションは実は一番楽しみにしていた TRICK でした。審査員の方も応募できることに驚き、審査員の方がたくさん入賞していたことでさらに驚きました。僕が一番好きだったのは、花の模様が動く様がとても綺麗だった beta_chelseaさんの作品 でした。正直どの作品も何がどうなってるのかわからないようなものでしたが、僕のRubyへの価値観を広げてくれました。 この日は夕方から城山公園にてOfficial Partyを楽しみました。色々な方がいらっしゃった中で、せっかくRubyKaigiに来たからには僕自身も何か一歩を踏み出してみようと思い海外の方に積極的に話しかけてみることにしました。海外の方に話しかけたことで、僕の中のRubyやgemへのコミット欲求がかなり高まりました。RubyKaigiに来るような海外の方は皆さん何かしらのgemやRuby自体にコミットしてらっしゃる方ばかりだったので話題が基本的にそのコミット内容についてでした。そのような方々の会話を聞いていると、僕の中で会話についていきたい欲求が高まりました。また、Matzとツーショットを撮ることにも成功しました!感無量です…。 Official Partyの後は、友人と合流後Yusuke Wadaさんが幹事をしてくださった二次会に参加していました。ここでも海外の方がたくさんいらっしゃる卓につくことができて貴重なお話を伺うことができました。 Ruby API の作者の Colbyさん ともお話をすることができて本当にすごかったです。(語彙力の欠如) 俺が幹事してるんでこい #rubykaigi pic.twitter.com/Xb31dGlbvH — Yusuke Wada (@yusukebe) 2025年4月16日 #rubyfriends 楽しかったです! pic.twitter.com/j45hyUf8Ka — Retasusan (@retasusan_510) 2025年4月16日 流石に体力の限界を感じたため、二次会の後にホテルに戻りDay1は終了です。(日付は超えていたのでもうDay2に突入していた可能性もあります) Day2 この日は前日の二次会ではしゃぎすぎたこともあり、正直あまりセッションを聞くことができませんでした、反省。 迷い込んだ先でKengo Hamasakiさんの Running JavaScript within Ruby を聞くことができました。このセッションは、JavaScriptをRubyで動かすセッションでQuickJSなどをRubyで実装し直すというような内容だった気がします。体調が悪かったことに加え、内容も難しく部分的にしか理解できなかったので、スタンプラリーをまわりながらブースの方でお話を伺いました。 なんとか休憩を挟みつつDay2のセッションを聴きに行き最後にLTを聴き、気づけばDay2が終わっていました。 夕方からは、エス・エム・エスの社員の方と学生支援の方で交流することになっていたので微妙に回復した体を引き摺りつつお話をしていました。エス・エム・エスの社員でRubyコミッターでもある 塩井さん ともお話をさせていただき、これまた貴重なお話を聞くことができました。(RubyKaigiで貴重なお話を聞くこと以外の方が少なかった) 社員の方との食事後も、大街道で出会ったRubyistと突発的な2次会が始まり、様々な会社の方と交流することができました。 #rubyfriends pic.twitter.com/onJWBwRomE — ありたそ (@alitaso346) 2025年4月17日 流石にカラオケに行くほどの元気はなかったので、その日はホテルに帰ってから大学の課題を二時間ほどこなした後に寝ました。 Day3 この日は、 Ruby Committers and the World から始まりました。コミッターの方々の議論を聴き、「Static Barrierなんてものが検討されているのか」と驚いたり、「Namespaceはまだまだ調整が必要なんだなぁ」と思ったりしてました。中でも互換性を無視して無くしたいものなどは面白い議論でした。 MatzのKeynoteでは、Ruby4.0のリリース予定が最後に全ての話題を持っていきました。あの瞬間の会場の盛り上がりは忘れられません。 クロージングトークでは、次回のRubyKaigiが函館で開催されることが発表されました。その時には、来年も参加することが僕の中で確定事項になっていました。 そんなこんなで、RubyKaigi 2025は幕を閉じましたが、そんなことで僕たちのRubyKaigiは終わりません。(!?) 友人と少し談笑したのちに、 さくらインターネットさんの打ち上げ に向かいます。 色々な方と交流したのち、Pixivさんの RubyMusicMixin に向かいました。 Mixinでは、これまた海外の方に積極的に話しかけました。ドイツやオーストラリア、カナダの方などとお話することができました。ここまでくればかなりRubyKaigiに染まっていました。 楽しい!fun!!! #rubykaigi pic.twitter.com/MW1bPvG4mj — Retasusan (@retasusan_510) 2025年4月18日 #rubyfriends pic.twitter.com/YLNKo6OuTw — Retasusan (@retasusan_510) 2025年4月18日 #rubyfriends pic.twitter.com/rBbKliSc72 — Retasusan (@retasusan_510) 2025年4月18日 ドイツの方とはかなり話が盛り上がり、ハリボーが好きな話をしたら来年のRubyKaigiではハリボーを持ってきてくださるとおっしゃってくださいました。グミ好きとしては来年のRubyKaigiには必ず参加したいところ。 この日は流石に疲れたので、深夜1時にはお暇させていただきました。 Day4 この日は、朝から友人とクロスフィットに参加していました。運動不足の自分にはかなりキツイ運動量で6名いた中で自分だけ途中でギブアップしてしまいました。日頃からちゃんと運動しようと決意しました。 Wellness up! Morning CrossFit at RubyKaigi Day4 終了しました! 皆さん本当にナイスガッツでした👍 @yfractal @bash0C7 @hetare70914 @h2z @ymneet 今回はクロスフィット松山様に全面協力いただきました。お近くにお住まいの方は、体験にお越しください! #rubykaigi #rubykaigi_hacomono pic.twitter.com/HWlhWZuTfh — hacomono Developers / hacomono プロダクトチーム公式 (@hacomono_Dev) 2025年4月19日 珍しく運動をした後はJR松山駅に荷物を預け、松山の街を彷徨っていたところ、Ruby Committerのシャツを着ている人物を発見し友人と突撃しました。後ほど判明したのですが、この方は 2024年のKeynote を担当なさった Samuelさん でした! 時に真面目な話を挟みながら道後温泉や神社、謎の寺、ジェラート店、DD4Dなどを一緒に観光してもらいました。本当にありがとうございましたSamuelさん! #rubyfriends #rubykaigi @ioquatix Dogo onsen!!! pic.twitter.com/n8xwSpvheL — Retasusan (@retasusan_510) 2025年4月19日 @retasusan_510 @rokuosan_dev @ioquatix #rubykaigi #rubyfriends pic.twitter.com/RCT64Jc9a0 — joker1007 (アルフォートおじさん) (@joker1007) 2025年4月19日 Rubyist増えた! #rubyfriends #rubykaigi pic.twitter.com/cNOuNWkpoT — joker1007 (アルフォートおじさん) (@joker1007) 2025年4月19日 その後、松山空港に向かいそこでも案の定Rubyistと交流しながら京都へと帰還し、僕のRubyKaigi2025は幕を閉じました。 最後に 僕は今回エス・エム・エスの 学生支援 を利用してRubyKaigiに参加させていただきました。 支援してくださったエス・エム・エスには本当に頭が上がらないです! 今回スポンサーブースでお話をしてくださった方々やRubyKaigiにてお話したたくさんの方々、勿論今回支援していただいたエス・エム・エスの皆様も本当にありがとうございました!来年のRubyKaigiでお会いした際にはまたよろしくお願いします! 今回のRubyKaigi期間中にお会いしたエス・エム・エスの社員の皆様の温かさや、イベントへの熱い想いにとても刺激を受けました! 今回ご支援いただいたご縁を大切に、もしご興味があれば、ぜひエス・エム・エスの採用情報をご覧いただき、応募も検討してみてください。 open.talentio.com
アバター
ご機嫌麗しゅうございます。 @kimukei です。 これは 【前編】Visual Regression Testing の内製化への道 🚀 〜Chromaticから代替ツールへ〜 の後編にあたります。 ではさっそく、どうやって Chromatic から代替ツールへ移行していったかを紹介していきます。 コンテキスト カイポケリニューアルでは 577 個の Story, kaipoke-ui 1 は 63 個ほどの Story を有している VRT しているスナップショット数はカイポケリニューアルで 969 枚、kaipoke-ui で 139 枚程度 カイポケリニューアルでは比較的動きの多い Modal や yagisan-reports 2 を使用した PDF を表示する Story が多く存在する これは、そんなカイポケリニューアルの pull request に実行する CI で Storybook の配信から VRT の実行とテストレポートの発行と配信までを 5 分程度に収めた物語。 また、それまで VRT の仕組みは Chromatic を使っていたため、なるべく VRT の体験は Chromatic のそれを損なわないように工夫しました。 ここで行う VRT としての CI と Storybook の配信と VRT の結果レポートの配信としての CD についてワークフローで行う処理の流れは以下のようになります。 Storybook を build Baseline 3 の取得 Storybook の撮影 撮影した画像と Baseline との比較(VRT) VRT レポートを作成 Storybook と VRT レポートをデプロイ & 配信 VRT で差分が検出されたときはマージをブロックする CI/CD の実行環境は GitHub Actions です。 VRT は reg-viz/storycap と reg-viz/reg-cli を用いて実現しています。 そこで、実現する中でいくつか知見が溜まったので紹介していきます。 Storybook, VRT について CI/CD 最適化の知見 GitHub Actions ランナーとコスト最適化 GitHub Actions hosted runner と AWS CodeBuild hosted runner のコスト比較 large runner についてホストが GitHub Actions hosted runner と AWS CodeBuild hosted runner とでコスト比較すると、CodeBuild の方が安いことがわかります。 GitHub Actions hosted runner pricing: https://docs.github.com/en/billing/managing-billing-for-your-products/managing-billing-for-github-actions/about-billing-for-github-actions#per-minute-rates-for-x64-powered-larger-runners AWS CodeBuild hosted runner pricing: https://aws.amazon.com/codebuild/pricing/ ※ GitHub Actions hosted runner は arm64 アーキテクチャだと安いのですが、今回 chrome や chromium と puppeteer を動かしつつ継続的にメンテナンスしていく都合上 arm64 アーキテクチャの runner の採用は見送っています 今回私が選定した runner は CPU のコア数が欲しくて CodeBuild(ap-northeast-1)の general1.xlarge ($0.1002/min) なのですが、近しい性能を出そうとすると GitHub Actions self hosted runner の Linux 32-core ($0.128/min)を選ぶことになります。 また、CodeBuild の runner はネットワーク上、S3 との通信が速いため Baseline の取得が早くなる利点などもありました。 ジョブ分割の落とし穴 VRT の時間的なネックはだいたい撮影にあります。枚数が多いのです。そこでよく sharding をして job を分割する手段が取られますが、この場合 job 分割のオーバーヘッドがなかなか無視できません。 具体的には以下のようなオーバーヘッドが乗ってきます。 runner の割り当て待ち 前の job で作られた生成物のダウンロード(前の job では生成物をアップロードするコストも発生します) runner の割り当て待ちについてですが、GitHub Actions では標準 runner ではないものを使うとしばしば pick されるまで遅い現象が発生しました。 CodeBuild では provisioning なども発生するため、だいたい job の最初の step が実行されるまで 30 秒程度かかってきました。 reg-viz/storycap には parallel オプションが、 reg-viz/reg-cli には concurrency オプションが提供されています。 そのためここではあえて job 分割を避けて large runner を用いてその中で大量に実行することでオーバーヘッドを極力なくしました。(そのために CPU コア数が欲しかった!) ちょうどこれくらい大きな Storybook だと、build した生成物も 50MB 強くらいの大きさで、GitHub Actions の標準 runner を使っていると動作が安定しないことなども起こっていましたが、CPU コア数が潤沢な runner を選ぶとだいたいそこそこ潤沢なメモリも付いてきます。これが撮影動作の安定化なども副産物的にもたらしてくれました。 ちなみに CodeBuild hosted runner を用いているとマシンリソースについてのメトリクスも同時に取れるので、最適な runner 探しも捗りました。GitHub Actions hosted runner でもメトリクスは見ようと思えば見れますが、見るためのスクリプトを入れたりなどが必要で「そういえば」とふと思った時に見られる準備をしていないことがほとんどです。 この辺はマシンスペックのチューニングと共に job と step のチューニングも同時に行うと良いでしょう。 ワークフロー全体のネック部分や pick 部分の可視化を行うのに Kesin11/actions-timeline がとても便利でした。設定や基盤が不要でワークフローに差し込むとすぐにこのような図が見られるようになります。 actions-timeline の図 まとめると、一見効率的に思えるジョブの分割ですが実際には 生成物のアップロード・ダウンロードに時間がかかる ジョブ間のリレーで待機時間が発生 ランナーの割り当て待ちが複数回発生 むしろ 1 つの大きなジョブで実行する方が、総合的なパイプライン実行時間が短くなることがあるということでした。 並列実行できる step をバシバシ並列実行させていく コマンドはこんな感じで並列実行できます。 jobs: parallel-commands: runs-on: ubuntu-latest steps: - name: Run commands in parallel run: | command1 & command2 & command3 & wait Baseline のダウンロードと Storybook の撮影は並列化可能でどちらも時間のかかる処理のため並列化したことで 1 分程度の短縮につながっています。 これも large runner のスペックがあるが故ですね。 配信基盤の選択とサイズ管理 Storybook と VRT レポートの配信について「どこ」に配信するかは重要な問題です。 よく使われるのは Amazon S3 でしょうか。今回は Private GitHub Pages を選択しています。 Private GitHub Pages の利点 AWS で認証付き配信基盤を構築するよりも、Private GitHub Pages を使用する方がセットアップが容易で管理コストも低くなります。 前提として、弊社ではエンジニアはほぼフルリモートで開発しています。 そのため何かを限定公開する際にはアクセスできるのは弊社の人間のみにする何かしらの仕組みが必要になります。 S3 では VPN の IP のみアクセス可能にするのがお手軽ですが、VPN 接続がめんどくさいという体験上のネックポイントが発生します。 組織の Google アカウントと連携した認証を用意するには工夫が必要です。 弊社の GitHub リポジトリは Google アカウントでの SAML 認証を必須化しているため、Private GitHub Pages で配信することで VPN 接続の煩わしさを解決しつつ同時にセキュアな限定配信を可能にしました。 ただし、GitHub Pages には制限があります。 アーティファクトのサイズ制限がシビア 同時デプロイリクエストに弱い(順次処理が基本) それぞれ次のセクションでどうやって対応したのか紹介します。 アーティファクトサイズ管理の重要性 GitHub Pages のデプロイは 特定のブランチ(ここでは gh-pages ブランチ)の内容を artifact 化し、アップロード アップロードした artifact を Pages にデプロイ という流れで行われます。 この artifact は 1GB 程度に収めておかないと deploy の失敗確率が上がったり、deploy に時間がかかるようになります。 GitHub Pages のパフォーマンスを維持するために、 VRT レポートから不要な画像(差分がないもの)を除去 変更がない場合はレポートを作成しない判断ロジックを導入 デプロイは可能な限りまとめて実行(同時リクエストの頻度を減らす) Pull Request の merge/close タイミングでの gh-pages ブランチの掃除 定期的な古いファイルの gh-pages ブランチの掃除 を行いました。 VRT レポートから不要な画像を除去できたり、変更がない場合はレポートを作成しないようにできたのは、フロントエンド部分を実装しているエンジニアにヒアリングしたところ PASSED の画像はほぼ見ていないとこがわかったためです。 PASSED の画像をレポートから除外することでフルだと 50MB くらいの容量のレポートが大抵 2~3MB になり 90%以上のサイズ削減が見込めます。 同時デプロイリクエストの制御 GitHub の Deployments はリクエストを排他的に処理します。つまり、実行中の Deployments があれば他の Deployments のリクエストは失敗します。 また、GitHub Pages の Build and deployment には「GitHub Actions」と「Deploy from a branch」の 2 種類のやり方があります。 前者は完全にこっちが deploy の面倒を見る設定で、後者がブランチが更新されたら自動で GitHub の方でデプロイしてくれるやり方です。 「Deploy from a branch」の設定は自動でやってくれるのは嬉しいのですが、ブランチの変更頻度が高いと同時実行性の点で難があります。 重複実行が回避されるように、実行中に新しい実行リクエストが来たら現在の実行をキャンセルし、新しい実行を始めるように設計されていて、この設定はいじれません。 そのため、ブランチの変更頻度が高い場合に実行リクエストが続々と来てしまうと常に最新のリクエストを処理しようとして最初のリクエストの変更が延々と Pages に反映されません。 これを避けるために前者の「GitHub Actions」で Pages デプロイする方法を取りました。 この方法ですと、ワークフロー内の concurrency 設定で同時実行された際の行動を制御できるようになります。 ここではデプロイのワークフローは他の実行によりキャンセルされないようにして、それぞれデプロイをやり切るようにしました。 その際、Deployments のリクエスト自体は排他的ですので、後続の Deployments リクエストは失敗する恐れがありますが、前のデプロイが終われば成功します。 そのため自動的に rerun できる仕組みを構築 4 し、artifact name はみな同一にしておいて last write win の状況を作り、upload artifact を行う job と deploy artifact を実行する job とを分け、deploy artifact を実行する job のみ rerun が行われるように組むことで順次デプロイは解消しつつ最終的には最新の artifact が Pages にデプロイされている状況を作り出しました。 VRT の最適化 これまで Chromatic を活用していたため、開発者のメンタルモデルには Chromatic の体験が根付いています。 今回 VRT の手法を Chromatic から移行させるにあたり、いかに Chromatic の体験に近づけていったか、それぞれポイントを紹介します。 storycap により生成される画像ファイル名と対象の Story の連携改善 Chromatic の体験として大きいのが、VRT で検知されたスナップショットで該当する Story のページへ即座に飛べることがあります。 この体験を移行するのに、 reg-viz/storycap で生成される画像ファイル名から Storybook の URL に変換できる関数を実装し、VRT レポートのサマリーを Pull Request にコメントすると共に変更を検知したスナップショットについてそれぞれ該当する Storybook のリンクをコメントと一緒に添えるようにしました。 例) GitHub Actions へのレポート reg-viz/reg-cli で生成した VRT レポート内に Storybook のリンクを配置するのは難しいですが、これならばそこまで体験を損ねずに VRT の結果と該当の Storybook への遷移がしやすくなります。 アニメーション対策とテスト安定性向上 VRT は flaky さとの戦いです。 VRT の安定性を高めるための施策をいくつか実施しました。 CSS アニメーションを無効化 JavaScript アニメーションを一時停止 タイミングに依存する要素の制御 最初の 2 つは DOM のテスティングでもよくやる推奨されるようなやり方ですし、紹介は割愛します。 タイミングに依存する要素の制御については、 parameters.screenshot.waitFor で頑張るのが良いのですが、構造上やむを得ないものは parameters.screenshot.delay でお茶を濁す感じになりました。 さらに、カイポケリニューアルでは複数のフォントを扱っているのですが、たまにフォント読み込みが終わっていないのに撮影されたために誤検出するケースもありました。 その問題については、すべてのフォント読み込みまで待つ util を実装しました 5 。 他にもスナップショットを安定させるためのあらゆる待ち条件を util 化し、各 Story で管理しやすくしました。 さらに、テストの不安定性(flaky)を検出するための仕組みも構築しました。具体的には、Baseline となる画像群(すでに S3 にアップロード済み)と、デフォルトブランチの最新コードから新たに生成した画像群を比較するワークフローを実装し、定期的(デイリー)かつ複数回実行することで、環境や実行タイミングによる差異を検出しています。 約 1000 枚のスナップショットを扱う規模では、単純な数の問題からも不安定性が生じやすくなります。このため、検出 → 対応 → 再確認のサイクルを地道に繰り返すことが信頼性向上のカギとなりました。特に flaky テストは確率的に発生するため、複数回の実行による検証は非常に重要です。 PDF のビジュアルテスト PDF 生成は yagisan-reports を使用しているのですが、PDF に対しても VRT を実施したいとなると何かしらの viewer が必要になります。 wojtekmaj/react-pdf を viewer に活用し、PDF の VRT を実現しています。 PDF は他のコンポーネントに比べるとレンダリングにやや時間がかかるため、撮影タイミングの制御は必須です。レンダリングを検知するための data-testid などを設定し、その要素の表示を待ってからスクリーンショットを撮影するようにしています。 VRT 判定基準の最適化 VRT における変更検知の閾値設定は、いわば「匠の塩加減」のようなものです。例えば Chromatic では diffThreshold のデフォルト値として .063 (6.3%) を採用しており、この閾値の決定には経験と試行錯誤が不可欠です。 https://www.chromatic.com/docs/threshold/ しかし、Chromatic の 6.3% をそのまま reg-viz/reg-cli に適用すると、検知感度に違いが生じ、偽陰性(変更があるのに検知されない)が増加する傾向がありました。 また、 reg-viz/reg-cli では、より詳細な閾値設定が可能になっています: -M, --matchingThreshold Matching threshold, ranges from 0 to 1. Smaller values make the comparison more sensitive. 0 by default. Specifically, you can set how much of a difference in the YIQ difference metric should be considered a different pixel. If there is a difference between pixels, it will be treated as "same pixel" if it is within this threshold. -T, --thresholdRate Rate threshold for detecting change. When the difference ratio of the image is larger than the set rate detects the change. Applied after matchingThreshold. 0 by default. -S, --thresholdPixel Pixel threshold for detecting change. When the difference pixel of the image is larger than the set pixel detects the change. This value takes precedence over thresholdRate. Applied after matchingThreshold. 0 by default. https://github.com/reg-viz/reg-cli?tab=readme-ov-file#options 様々なパラメータを試した結果、最終的に --matchingThreshold 0.011 --thresholdPixel 100 という値に落ち着きました。閾値調整の基本姿勢としては、まず 0 に近い値(高感度)から始め、偽陽性(変更と検出されたくないのに検知される)が目立つようであれば徐々に値を上げていく方法が効果的です。これは偽陰性の方が発見・対応が難しいためです。 また、開発者のメンタルモデルとして、画像差分を画面全体の割合で捉えるよりも、変更部分のピクセル数で判断することが多いと観察されたため、割合ベース(thresholdRate)ではなくピクセル数ベース(thresholdPixel)での検知手法を採用しました。大きな画面であっても、開発者は画面全体ではなく構成コンポーネント単位で変更を認識しているためです。 VRT の承認プロセスとマージブロックの連動 プルリクエストのマージ制御には、GitHub の Branch protection rule にある「Require status checks to pass before merging」機能が効果的です。これにより、ステータスチェックとマージ条件を連動できます。 ただし、VRT を実施するワークフローでマージブロックを直接制御しようとすると問題が生じます。承認プロセスという強制的に成功とみなす「裏口的な手法」がワークフロー自体に混入してしまい、全体の見通しが悪くなりメンテナンス性を損なう恐れがあります。そこで私たちは、マージブロック制御を別の仕組みとして実装しました。 具体的なアプローチは以下の通りです: VRT で差分検出時、プルリクエストに専用のラベルを付与 このラベルが存在する場合、ステータスを pending に設定 ラベルが外れた場合、ステータスを success に更新 このマージブロック制御には on.pull_request.types: [labeled, unlabeled] イベントを活用し、ラベルの付け外しという単純な操作で VRT の承認管理を実現しています。 また、開発者からのフィードバックを受け、VRT 承認待ち状態ではコミットステータスを「failure」ではなく「pending」に設定するよう改善しました。pending 状態はブラウザタブで以下のように表示され、対応状況が視覚的に把握しやすくなっています。 ステータスが失敗の見え方 ステータスがペンディングの見え方 これは最新のコミットに対する status を制御することで実現できます。GitHub の REST API( Create a commit status )を使って、VRT の承認状態に基づいて最新コミットのステータスを操作し、「Require status checks to pass before merging」で設定している job 名のコンテキストで付与することでブロック制御と両立させました。 この一連の処理フローは以下のとおりです: VRT で差分検出時、GitHub App のトークンを使用 6 してプルリクエストにマージブロック用ラベルを付与 このラベルが付いている場合、最新コミットのステータスを特定の job 名のコンテキストで pending に設定 VRT の変更を承認する場合、VRT 結果を案内するコメント内のチェックボックスにチェックを入れる(issue_comment.types: edited イベントが発火) コメント編集イベントをトリガーに、承認コメントであることを確認してマージブロック用ラベルを除去 ラベル削除により、最新コミットのステータスを job 名のコンテキストで success に更新 これでマージが可能になる この仕組みにより、意図しないビジュアル変更のマージを防止しつつ、意図的な変更は簡単な承認プロセスで対応できるワークフローを実現しました。 まとめ カイポケリニューアルのプルリクエストに対する CI 処理で、Storybook の配信から VRT の実行、テストレポートの配信までを 5 分程度に収めるために実施した主な最適化ポイントは以下の通りです: ランナー選定の最適化 : AWS CodeBuild hosted runner の採用によりコスト効率を改善 適切なマシンスペックの選定により VRT のパフォーマンスを大幅に向上 ジョブ構成の最適化 : 多数の小さなジョブへの分割ではなく、単一の大きなジョブ内での並列処理を選択 並列実行可能なステップを特定し、効率的な実行パイプラインを構築 配信基盤の効率化 : Private GitHub Pages を活用した認証付き配信の簡素化 アーティファクトサイズの厳格な管理による安定したデプロイ デプロイメントリクエストの効率的な制御 VRT の開発者体験向上 : Chromatic に近い使用感を再現し、移行コストを最小化 アニメーションなどの不安定要素に対する堅牢な対策 効果的な判定基準の設定による誤検出の最小化 直感的な承認プロセスとコミットステータスの連動 これらの最適化により、577 個の Story と 969 枚のスナップショットを扱う大規模 VRT プロセスを約 5 分で完了できるようになりました。この改善は開発サイクル全体の効率化に貢献し、開発者体験の向上にもつながっています。 また、この移行を通して VRT や Storybook を配信するのに支払っていた月々の支払いを 90% 近く削減できました。 内製している UI コンポーネント群。Chakra UI をベースに作っている。 ↩ PDF の生成に利用している帳票発行エンジン。 https://denkiyagi.jp/yagisan-reports/ ↩ VRT をする際の比較元となる main branch のスナップショットを事前に S3 にアップロードしています。 ↩ https://github.com/orgs/community/discussions/67654#discussioncomment-8038649 が参考になると思います ↩ FontFace API の loaded プロパティを活用し、プロジェクトで使用するすべてのフォントを列挙して、それぞれの loaded() の Promise が解決するまで待機する実装としました。参考: https://developer.mozilla.org/en-US/docs/Web/API/FontFace/loaded ↩ GitHub App のトークンを使用する理由はデフォルトトークンだとイベントが後続のワークフローにフックされない GitHub Actions の仕様のためです。 ↩
アバター
はじめまして、都内の大学でコンピュータサイエンスを専攻している小野です。インターネット上ではゆう猫( @yuneko1127 )と名乗っています。RubyKaigi 2025には、株式会社エス・エム・エスから学生支援を受けて参加しました。この記事では、RubyKaigiに学生が初めて参加した経験やRubyKaigi 2025の面白かったセッションなどについて紹介します。 rubykaigi.org 参加の経緯 自分は専攻として情報科学を学習しているものの、専門はコンピュータビジョンとヒューマンコンピュータインタラクションで、プログラミング言語処理やRubyに特に詳しいというわけでもなく、RubyKaigiにはひょんな理由から参加することになりました。 自分のプログラミングは高校生のときにTechnovation Girlsというアプリ開発コンテストに参加したことから、本格的に始まりました。コンテスト後もプログラミングやコンピュータのことを勉強するのが好きで、気付いたら情報科学科に進学していました。大学進学を機に、Technovation Girlsへ日本から参加する学生を支援しているNPO法人Waffleで運営インターンを始めました。そのSlackでWeb開発の勉強をしたいと呟いたら、カリキュラム・マネージャーをやっている鳥井さん( @yotii23 )からRailsなら教えられるよと言われ、RailsからRubyを触ることになりました。その勉強会をやる中で、鳥井さんからRubyKaigiの学生支援があるから是非とおすすめされ、参加しました。 自分はRubyがネイティブ言語というわけでも、Rubyでプロダクトコードを書いているわけでもないですが、Rubyistに誘われ、RubyKaigiに参加しました。 参加の前に RubyKaigiに参加できると決まってから、楽しみだなという気持ちと共に、自分が行って大丈夫なのだろうか、場違いなのではないだろうかという不安に襲われました。結論を言ってしまえば、これは杞憂だったのですが、これを杞憂にするためにやったことが少しだけあります。 一つ目は、スケジュールを見て(翻訳も見て)何個かこれは見て面白いだろうし、分かりそうだなというものを決めておくことです。自分は、Rubyの細かい仕様はわからないけど、オートマトンや正規表現など情報科学の学問的な話やメディア系の情報処理(今回話題の音を出す系)の話は分かるので、そのようなものを積極的に見るようにしていました。 二つ目は、過去のRubyKaigiを流し見することです。実際に過去のセッションを見てみると自分がどのくらいわからないのかの検討ができるようになり、ついでに知識もつきます。また、去年あの話をしていた人だ!と一方的に知っている人が増えます。自分は、RubyKaigiの荷物をまとめているときに、RubyKaigi 2024の@tompngさんのKeynoteを見て、今回のTRICKを心から楽しみにしていました。 www.youtube.com 面白かったセッションの話 ここからは、たくさんあるセッションの中で個人的に感動した、面白かったセッションの話を少しだけしたいと思います。 Make Parsers Compatible Using Automata Learning Day1のKeynote後のMain Roomのセッションです。Rubyには2種類のParserが実装されていて、それぞれの互換性を確認する方法が問題になっています。たくさんのプログラムをパースして、その差分を確認するなど量的に確認することもできますが、この発表では、パーサーの一部をオートマトンとして表現することによって、その差分を明らかにします。パーサーをオートマトンの表現に変換することは、オートマトン学習という手法を利用することによって可能になります。実際にパーサーの一部をオートマトン学習によってオートマトン表現に変換することによって、パーサー間にある互換性の問題を発見することもできているそうです。 この発表の個人的なぐっと来るポイントは、オートマトン学習などの情報科学のアカデミックな知見が、実際にRubyのパーサーのバグの発見や互換性の維持に利用されているというところです。このようにRubyへ貢献する方法もあるのかと感動しました。ちょうど今学期に受講しているプログラミング言語処理の科目の直前の授業で、正規表現と有限オートマトンの話を聞いていたので、あの知識がここで今まさに使われていると感動していました。 TRICK 2025: Episode I Day1最後に行われた、見たことがない奇妙なコードをたくさん見ることのできるセッションです。先ほど説明したように、自分はTRICKを非常に楽しみにしていました。それぞれのTRICKに関して何も説明できないですし、会場でもひたすらにこんなことまでできるのか!と驚いていました。興味深いとか役に立ったとかではなく、ただただ驚愕し、興奮するセッションでした。この後、自分も奇妙なコードを書いてみたいと思い、RubyKaigiが終わった後にTRICKの審査員であるmameさんの著作『 あなたの知らない超絶技巧プログラミングの世界 』をすぐに読み始め、あと残されているのは書くことだけです。 Ruby Committers and the World CRubyのCommitterがステージに上がり、Rubyについて話し合うセッションです。Rubyの仕様に詳しいわけではないので、内容がよくわかったわけではないですが、Rubyのような巨大なOSSがどのように維持運営されているかの一端を垣間見ることができて非常に興味深かったです。MatzのkeynoteでもあったようにRubyが公開されてから30年経っても、現状維持だけではなく、修正や更新されて、たくさんのコミッターがいることがRubyとそのコミュニティの豊かさを示しているなとしみじみしていました。それと同時に、この話をよくわかりたいと思い、Rubyの使い方だけではなく、Rubyがどのように作られているのかにも興味がわきました。 RubyKaigiはどういうものだったか RubyKaigiは、単にプログラミング言語Rubyの言語処理に関する会議、といってしまうことのできないような、多種多様で魅力的なカンファレンスでした。セッションだけでなく、After PartyやDrink up、企業ブースや廊下や街中での会話まですべてがRubyKaigiの体験を構成していて、また来たい!と思うような会議でした。 そして、RubyKaigiに参加して、一番喚起された感情はRubyをもっと書きたいという衝動です。自分はプログラミング言語にあまりこだわりがないのですが、Rubyを手に馴染ませて、最初に手に取る言語にしたいと思うようになりました。そしてこのRubyKaigiから、何かしらの形でRubyのコミュニティに関わっていきたい、そして貢献したいと思いました。 松山、ありがとうございました。RubyKaigi 2026、函館でまた会いましょう! 『世界の霧』というアプリで記録されている松山市での移動履歴
アバター
はじめに こんにちは、カイポケのリニューアルプロジェクトを担当しているエンジニアの田所( @ikuma-t )です。昨年10月に入社し、現在は請求関連の機能の開発を行っています。 カイポケが価値を提供する介護業界について、日常的には馴染みがないという方も多いかもしれません。私も入社以前は後期高齢社会における社会課題の1つであると漠然と認識している程度で、介護業界の制度についてはあまり詳しくありませんでした。「介護業界については未経験でも大丈夫」という言葉を信じ、この会社に入社しました。 今回は私のように未経験から介護業界へチャレンジするメンバーを支える、介護業界理解のためのワークショップ研修について紹介します。この記事では実際に介護業界に触れてみて感じた介護業界の難しさを踏まえた上で、研修ではどのようなことを得られるのか、また実際に研修を経てプロジェクトに参画してみての感想をお伝えします。 介護業界の難しさは細部の複雑さにある 制度自体の入り口はそこまで難しくない 約半年という期間ではありますが、介護業界に向き合って感じたのは「制度自体の入り口はそこまで難しくない」ということです。 介護予防・日常生活支援総合事業のサービス利用の流れ | 介護保険の解説 | 介護事業所・生活関連情報検索「介護サービス情報公表システム」 より 引用は厚生労働省の介護サービス利用までの流れです。「要介護1」であったり、「介護予防事業」などの見慣れない単語はあるかもしれませんが、利用者が介護を受けるまでのフローは(図自体が簡略化されているということもありますが)意外とシンプルです。 利用者が市区町村の役所に相談 利用者の情報を入力に、介護度(どの程度の介護を必要とするか)を出力する 介護度に応じた介護の計画を立てる 計画に基づいた介護サービスを受ける 自身の周囲に実際に介護を受けている/提供している方がいなくても、なんとなくお手持ちの健康保険証や、普段ニュースで見かける話題から、ぼんやりと大まかな流れを想像できるのではないでしょうか。 多様な環境に対応するために複雑にならざるを得ない 一方で実際に開発を進めていくとなると、当然先ほど示したフローチャートの範囲の知識だけではすべてを賄うことはできません。「おおよそのケースではこのフローに則るが、一部外れるケースもありうる」ということがよくあります。 制度は実際に介護を提供するためにあるものですが、その介護の形は人によってさまざまです。要介護者の症状や、要介護者のまわりの家族のあり方の変化、介護サービスを提供する行政の財政状況など複数の要因が絡み合い、それらに合わせて制度のあり方は変化しています。 このことは介護保険法の変遷や、今も3年に一度法改正が行われていることからもみて取れるでしょう。 また介護業界にあまり馴染みのない人にとっては、例外的なケースは制度以前にそれが必要となる状況自体を想像するのが難しく、余計に難易度が高く感じられると思います。 メンタルモデルをうまく構築することで早く理解できるようになる 新しい概念を自分のものにするための方法にはさまざまなアプローチがありますが、その一つに「メンタルモデルの構築」があります。以下はプログラミングの文脈で書かれたメンタルモデルについての記事からの引用です。メンタルモデルの定義について書かれた内容ではありませんが、メンタルモデルを成熟させることの意味が書かれているため引用させていただきました。 未知の概念を使えるようにするには、その概念についてイメージを頭に思い浮かべられるようにする必要があります。ここで浮かべるイメージをその概念の「メンタルモデル」と言うことにしましょう。僕らはより高度な概念を理解するためにそのメンタルモデルを思い浮かべながら文章を追いかけます。もしメンタルモデルと文章に矛盾が発生したらメンタルモデルを修正します。そうして矛盾が発生するごとに今までの事象を全てうまく説明できるように修正していき、メンタルモデルの完成度を高めていくのです。 はじめに #Haskell - Qiita 理解の基礎となるメンタルモデルを築くことにより、そことの類似性や差分から新しい概念を早く理解できるようになります。 介護業界の理解においても、例外的なケースと大枠のフローをひとくくりに摂取しようとすると、その情報量に圧倒されるか、あるいは1つ1つの情報の咀嚼に時間がかかってしまいます。そのためはじめの段階でしっかりとしたメンタルモデルを構築することが、介護業界理解の鍵となります。 ワークショップ型研修でメンタルモデルを構築する 介護業界理解のため、中途入社者向けにワークショップ型の研修が実施されています。 オフィスに集まり、1日かけてドメインエキスパートの方と介護業界についての理解を深めていきます。 東京タワーが見える会議室で1日学びます。 介護業界を、考えて、書いて、理解する ワークショップの中では講義パートとグループワークのパートがあり、グループワークのパートでは与えられたテーマを元に、介護業界について考えるという内容です。 ワークショップで扱うテーマは複数ありますが、一例として以下の内容に取り組みます。 チームでアウトプットすることで曖昧な知識に気がつくことができる テーマについて、まずは何も調べずに自分たちがすでに知っていることを元に仮説を話し合い、その後ネットで調べた情報やドメインエキスパートの方との会話を元に、介護を受けるためのフローを書き起こしていきます。 自分たちで手を動かしながら考えるため、単純に同じ量を座学で理解するよりもたくさんの気付きを得られるのがワークショップ型研修の良いところです。 この記事の冒頭に掲載したようなフローチャートを座学で学習する場合、ざっと見て「なんとなくこういう感じなのだな」と理解を止めてしまうことも多いでしょう。一方グループワークではチームに向けて自分の認識を共有しながらアウトプットしていく必要があるため、曖昧な部分を素通りすることはできません。 実際にワークショップを体験した際にも、「介護受けたいなら、たぶん最初は役所行っとく...よね?」といった会話からはじまり、なんとなく知っているけど、説明できない部分を1つ1つ明らかにすることで理解を深めていきました。 実際にグループで考えたフロー図 実際に介護の現場で長年働いてきたドメインエキスパートと一緒に学ぶ このワークショップ型の研修の講師役は、実際に介護の現場で長年働いてきたドメインエキスパートの方たちです。 実際に自分たちでテーマに対して調べていくと色々と細かいところが気になってくるのですが、その際にはドメインエキスパートの方に気軽に質問してその場で疑問を解消することができました。 ドメインエキスパートの方は研修のときだけでなく、実際のプロジェクトでもお世話になっており *1 、わからないことがあればSlackで気軽に確認したり、新しいエピックの開始時には、そのドメインの勉強会を実施いただいたりしています。 「ドメインエキスパートに気軽に質問できる環境」といっても、ほぼリモートかつ初対面だとなかなか質問しづらいものです。入社してすぐにドメインエキスパートの方と対面でコミュニケーションを取れる機会があることで、以降の開発時のコミュニケーションにおける安心感が違うと個人的には感じています。 実際に研修を受けてからプロジェクトに配属されてみて 実際に入社時研修を終えてプロジェクトに配属された際、当時チームが開発していた内容が研修に出てこないものだったため、(研修の理解度はばっちりだと思っていたこともあり)非常に焦った記憶があります。 ただしっかりと向き合ってみると、研修で培ったメンタルモデルをベースに、どの介護のパターンで、どこの業務で使うものかをスッと理解することができ、チームの開発にもスムーズに合流することができました。 *2 おわりに この後期高齢社会において介護業界に向き合うことは社会的意義のあることで、私もそこに共感して弊社に入社しました。 一方でエンジニアとして介護業界に向きあうことの魅力はそれだけではなく、この広く深い制度をどう理解し、保守性の高い実装に落とし込んでいくかを考える部分にもあると考えています。 今回はその理解を深めるための取り組みの1つとして、業界理解のためのワークショップ研修をご紹介しました。この記事の内容が介護業界に興味はあるけど、業界知識の不足に対して不安に思われている方の参考になれば嬉しいです! カイポケ組織におけるドメイン知識の向き合い方について、以下の記事でも触れられているのでご覧いただければと思います。 tech.bm-sms.co.jp *1 : このブログ記事を書く際にもお世話になっています。 *2 : 開発チームやオンボーディングのメンター、ドメインエキスパートなど、気軽に聞ける環境があるということも寄与しています。
アバター
こんにちは、介護/障害福祉事業者向け経営支援サービス「カイポケ」のリニューアルプロジェクトでモニタリングやオブザーバビリティ周りを担当している加我 ( @TAKA_0411 ) です。 4/11に開催されたPHPカンファレンス小田原 (以下ぺちおだ) 2025の前夜祭にて「推しのコミュニティはなんぼあってもいい」というタイトルで5分LTをしてきました。本記事ではLTの内容に触れつつ、以下の観点でまとめます。 このテーマを選んだ理由 登壇後の反響 私がぺちおだに参加する理由 PHPカンファレンス小田原2025 イベント公式サイト phpcon-odawara.jp PHPカンファレンス小田原2025 前夜祭 phpcon-odawara.connpass.com 登壇スライド speakerdeck.com このテーマを選んだ理由 YAPC::Hiroshima 2024にてそーだいさん ( @soudai1025 ) が「自分の好きな技術領域やそのコミュニティにいても良いし、興味のある技術的に近い隣のコミュニティに参加するのも良い」という話をしていたのが印象的で、自分の体験も交えて発表したいと考えたのがきっかけです。 www.youtube.com 私は最近、主にJAWS-UGのイベントで運営・登壇・参加していますが、JAWS-UGとPHPコミュニティの距離は遠くないと感じています。「技術的に近い隣のコミュニティに参加すること」の意義を発信するにはぺちおだは最適な場だと思い登壇を決めました。 発表内容を考える中で、PHPカンファレンス北海道2024にAWS界隈の知人を誘ったエピソードが思い浮かびました。 知人は「PHPの話はあまり理解できなかったが、開発に役立つ一般的な知識を学び、自分の独学の答え合わせができた。何よりPHPコミュニティの人と話せて楽しかった」と言ってくれました。これこそ「興味のある隣のコミュニティに参加する」ことの価値だと実感し、複数のコミュニティに参加するメリットや、参加者が楽しめる要素について考えた結果が今回の発表スライドです。 今回のぺちおだ2025には札幌在住のAWS界隈の知人3名を誘い、4人で参加しました。全員PHPには詳しくなく主にAWSを扱っています。彼らにも参加後の感想をブログに書いてもらう予定で、私の仮説がどうだったかを楽しみにしています。 私自身、今はオブザーバビリティ領域に強い関心がありますが、AWSコミュニティやPHPコミュニティ、最近だとSREコミュニティを経て得られた学びを通じて「自分はオブザーバビリティに興味がある」と気づきました。AWSだけに詳しくてもWebアプリケーションのことが分からなければサービスの問題解決はできません。Production ReadyなWebアプリケーションを開発するスキルがない自分が「動いているWebアプリケーションで何が起きているのか、問題解決のための技術や考え方を学ぼう」と思えたのは、複数のコミュニティに参加したからこそ得られた気づきです。 登壇後の反響 LT登壇後に「実は私もJAWS-UGに参加してみたいと思っていて…」という相談を受けとても嬉しく思いました。あるJAWS-UGイベントへの参加を迷っているとのことでしたが、私は現地参加できずフォローが難しい状況でした。そこで、技術的なバックグラウンドが近い知人やコミュニケーション力のある知人を紹介しつつまずは参加してみてほしいと伝えたところ、当日のX(旧Twitter)で楽しんでいる様子が伝わってきました。勉強会後の懇親会にも参加し楽しんでもらえたようで、背中を押した身としても嬉しい限りです。 私自身がイベントを楽しむのも大切ですが、「技術的に近い隣のコミュニティ」の人の参加を支援したり、初参加の人と運営をつなげたりすることも最近の楽しみの一つになりつつあります。これはYAPC::Hiroshima 2024でそーだいさんのスライドにあった「次の人に水の場所を教えてあげる」にも通じるかもしれません。 私がぺちおだに参加する理由 私が関わっているカイポケのリニューアルプロジェクトはPHP以外の言語で開発されており、私自身も現在PHPを積極的に書いているわけではありません。過去にPHPを使ったプロジェクトに携わったことはありますが、それも今では昔の話です。 それでも昨年に続き今年もぺちおだに参加した理由は、「PHPコミュニティの居心地の良さ」と「ぺちおだの圧倒的なホスピタリティ」にあります。 PHPコミュニティの居心地が良い 今でこそ色々な技術コミュニティに参加している私ですが、私が初めて参加した技術コミュニティはJAWS-UG(AWS User Group – Japan)のJAWS DAYS 2014で、その次がPHPカンファレンス2015でした。特にPHPカンファレンス2015では初参加にもかかわらずスタッフに応募し、多くのPHPエンジニアの先輩や友人ができました。 一昨年まではカンファレンス運営スタッフとしても積極的に参加していましたが、地元北海道へのUターンを機に参加できなくなったコミュニティも増えました。PHPコミュニティもその一つです。そんな状況でのぺちおだ2025参加には不安もありましたが、PHPコミュニティの皆さんは温かく迎えてくれました。こうした居心地の良さがあるため、日程が合えばまた参加したいと思えるのが私にとってのPHPコミュニティです。 ぺちおだの圧倒的なホスピタリティ ぺちおだでは参加者が楽しめるような仕組みがいくつもあります。昨年のぺちおだ2024では前夜祭にIRT (Interactive Round Table) が行われ、本編参加前に参加者同士で交流を深めることができました。 PHPカンファレンス福岡2023での体験が色濃いのですが、全然野菜・前夜祭があったことで、みんなと仲良くなれた体験、あの設計の素晴らしさを小田原でも再現したかったため、公式で前夜祭を企画しました。 コミュニケーションに重きをおきたいため、IRTを行い、そのあとはみんなで飲みました🍺 asumikam.com 参考 : IRT: Interactive Round Table を実施します blog.phperkaigi.jp 去年に引き続き行われた「1分間フィードバック」に加え、今年は参加者の交流を深めるための新たな取り組みとして「ぺちおだ大合戦」が実施されました。 前夜祭 6人程度で1つのテーブルを囲み、乾杯と自己紹介(テーマは事前に運営から提示)が行われました。ドリンク片手に小田原の美味しいピザを食べながら談笑し、その後セッションとLTが始まります。ぺちおだ2025では「1分間フィードバック」という仕組みがあり、登壇者の発表後に1分間で付箋にフィードバックを書き、ホワイトボードに貼るというものでした。会期後のアンケートよりも気軽にフィードバックでき、印象が新鮮なうちに意見を伝えられる良い取り組みだと感じました。 付箋によるフィードバック 当日 一通りセッションとLTを聴き終わった夕方からは3人1組の「ぺちおだ大合戦」というチーム戦があり、参加者同士で大いに盛り上がりました。 ぺちおだでは、参加者同士のコミュニケーションを大切な軸の一つとしています。それを体現するコンテンツとして、参加者同士でランダムなチームを組んで競い合う、チーム対抗バトルを開催しました⚔️ note.com note.com ぺちおだ大合戦は春の陣・夏の陣・秋の陣・冬の陣の4つに分かれています。 春の陣:スポンサーブース巡り 夏の陣:PHPの関数をテーマにしたゲーム 秋の陣:PHPやWeb、小田原に関するペーパーテスト 冬の陣:HTTPステータスコード百人一首 各陣にはチートシートやドキュメント、公式noteに散りばめられたヒントもあり、多くの参加者が迷わず楽しめたと思います。特に冬の陣のHTTPステータスコード百人一首は、PHPに馴染みのない私や知人も問題なく参加でき盛り上がることができました。読み上げられたステータスコードに対して「これは自信があった!」とか「一度も使ったことがない」などの短い感想戦が繰り広げられていたのが印象深いです。 まとめ PHPカンファレンス小田原2025にて技術コミュニティについて考え発表してきた話でした。私はここ数年でそこそこ登壇するようになったのですが、5分のLTは人生初でした。資料作成にも発表の時間調整にも苦労しましたが、多くの方からポジティブな反響を頂けたので苦労の甲斐がありました。次はJAWS-UGにてPHPコミュニティに参加してみようという逆側の発表を画策しています。 私の主観ですが、ぺちおだは「学び」だけでなく、参加者同士の交流やイベント自体を楽しむことを重視しているカンファレンスだと感じます。現在、業務でPHPを使っていない私のような人でも参加しやすく、随所に楽しめる工夫が凝らされていました。コミュニティ運営に携わる身としても多くの学びがありました。改めましてぺちおだに関わる全てのみなさま、ありがとうございました & お疲れ様でした。 最後に一膳飯屋 八起さん (ぺちおだ会場のお隣) で食べた「小田原”鯵の鍋焼きご飯”」 がはちゃめちゃに美味しかったので置いておきます。 美味すぎワロタ #phpcon_odawara pic.twitter.com/Tg2AOJKAWS — しめじ/Kaga (@TAKA_0411) 2025年4月13日
アバター
皆さんはじめまして。 慶應義塾大学の中村颯といいます。 X(Twitter)ではみゅーら( @lit_myura )でやってるのでもしよければお話しましょう...! 僕は元々中学の時にプログラミング塾に通っていて、そこで出会ったのがRubyでした。そこから早8年位経って、今では元々通っていたところで僕がRubyを教えています。 そんな中で教え子たちのレベルがどんどん上がる中、僕が最新情報をキャッチアップしないで何が出来るのかと思っていたところ、RubyKaigi2025を見つけました。 今回僕はエス・エム・エスさんの学生支援を受けて、人生で初めてRubyKaigiに参加しました。実はテックカンファレンスへの参加自体が初めてであり、四国を訪れるのも初めてです。とても緊張しました。 今回はそのレポートとなります。 もしよければ最後まで読んでもらえると幸いです。 RubyKaigiに参加してみて まず、何よりも本当に楽しい3日間でした。正直なところ、内容の8割ほどは理解が及ばず、自分の力や知識では分からないことだらけでしたが、それでも十分すぎるほどの刺激がありました。 特に、会場ではブースにいる時間が長く、セッションを聞くよりも1対1でお話できる時間が多かったのもあって、わからないことも含めてじっくり対話できたのがとても良かったです。そして、やっぱり改めて感じたのは「みんな、本当にRubyが好きなんだな」ということ。 趣味でRubyを使用しているという方も多く「仕事では使わないけど、自分でなにか作るならRubyを触る」なんて声も聞きました。そのように愛されているプログラム言語が日本で生まれたRubyであること、それが自分にとっても大切な言語であることは本当に純粋に嬉しいなと思いました。 あと全体的にノベルティのセンスが本当に良くて終始テンションが上っていました。 御朱印帳とか、今治産のタオルとか。これからも使い続ける事になりそうなものばかりで思い出の数々です。 ↑個人的には砥部焼にワクワクしちゃいました。 Rubyに対する意識 僕自身もともとRubyへの愛着はありましたが、今回のRubyKaigiを通して改めて「Rubyを使えばなんでもできる状態」に自分を持っていきたいという気持ちが強くなりました。 先程も記載した通り、セッションの多くは理解するのが厳しかったです。 ただ、それ以上に登壇者たちが本当に楽しそうに、情熱を持って話している姿が印象的でした。内容が完全に理解できなくても「この人の話は面白そうだな」と思わせる力がありました。特にDAY1冒頭のima1zumiさんのセッションでは、文字コードに対する「好き」が伝わってきて、RubyKaigiへの期待が爆上がりしちゃいました。 そして、DAY1最後に行われた「TRICK 2025: Episode I」では、今まで自分が見てこなかったようなタイプのコーディングを目にしました。自分はこれまでRubyを「Webサービスを作るためのバックエンド言語」として扱ってきて、その目的のために効率や完成度、スピード、そしてユーザビリティを重視することが当たり前だと考えていました。だからこそ、最近ではAIを使ってコーディングすることも増え、何より「完成品」に価値があると思い込んでいた節があります。 しかし「TRICK 2025: Episode I」の場では、コードそのものを楽しむ人たちの姿がありました。誰かの役に立つコードではなく、自分の工夫や遊び心が詰まったコードを披露し合う様子を見て「ああ、自分で書くっていう行為自体にも、楽しさってあったよな」と思い出しました。 そんな経験から「自分が心から楽しめる、自分にとっての絶対的な言語」があるって、すごく素敵なことなんだと感じました。もちろんサービスを作ることや、複数の言語を使いこなすことも大切ですが、「ものづくりの過程そのもの」を楽しめるかどうかで、その人の意識や取り組み方って大きく変わってくるんだなと改めて実感しました。 もちろん処理速度や適材適所の選択はあると思いますが、どんなものでもRubyでつくれる自分でありたいし、Rubyを通じて楽しさを感じ続けたいと思っています。普段はWebサービスの開発などでしかRubyに触れない僕ですが、それ以外の部分にも触れてみようって思うきっかけになりました。PicoRubyとかの話も面白かったので、組み込み型のRubyとかから挑戦してみるつもりです。まずはいわゆるLチカからはじめてみます。 また、JITによる高速化の取り組みなども含めて、Rubyを進化させようと本気で取り組んでいる方が多くて、その熱量がすごいと感じました。でもそれが、何かに追われているような雰囲気ではなく、「自分が楽しいからやってる」という雰囲気なのが印象的でした。それぞれが自分のやりたいことを自由にやっていて、それがちゃんとRubyの未来につながっているというのは本当に素晴らしいなと思います。 その中で、あれだけあたたかく話しかけてくれる人たちがいるRubyコミュニティに、これからも関わっていきたいと思いました。 地域.rbなども含めて、今後もいろんな形で参加したいと思っています(東京近郊でおすすめの場所があれば教えて下さい)。 まとめ RubyKaigi2025を通じてこのような場所にいられること自体が幸せで、このコミュニティの一員になっていきたい、と思えるような時間でした。 今の僕はまだRubyをシンプルな使い方しかできていません。でも、これからもっと深く学んでいけば、見えるものも話せることも増えていくはず。今以上にRubyが楽しくなる未来が待っている、そんな希望が持てた3日間でした。 また、海外の参加者の多さにも驚きました。規模が本当に大きくて「このサイズが初めてのテックカンファレンス」というのは贅沢だったなと…。自分が興味ある分野で、生の英語や世界中の人の声を直接聞けるというのは本当に貴重な機会だったと思います。 しかし、個人的な反省点が1つだけあります。名刺を持っていかなかったのは、かなりもったいなかったです。もっと交流できるチャンスがあったのに…と少し悔しい気持ちもあります。次回はしっかり準備して、もっといろんな方とつながれるようにしたいです。 本やサイン会などを通して、近い距離感で学べる空気感も素敵でした。それぞれが違う視点で世界を見ているのに、目指している先は同じ。動き方は違っても、みんながRubyの未来を見て行動している。そういう姿にたくさん出会えたことが、何よりの収穫でした。 改めて、助けてくださった皆さん、お話ししてくださった皆さん、本当にありがとうございました。 また、支援してくださったエス・エム・エスさんにも改めて感謝申し上げます。 最高のRubyKaigiでした。 次のRubyKaigiやKaigi on Rails、そして他のRubyコミュニティでも、また皆さんとお会いできるのを楽しみにしています!
アバター
合同会社 makigai(マキガイ) の貝瀬です。2024年6月からスクラムマスターとして、介護/障害福祉事業者向け経営支援サービス「カイポケ」に関わる組織やプロセスの改善を支援しています。 カイポケリニューアルプロジェクトでは、LeSS(Large Scale Scrum:大規模スクラム)を導入しています。本記事では2025年1月に実施した座談会の残りの部分(Part3)をご紹介します。 Part1、Part2については以下の記事をご参照ください。 tech.bm-sms.co.jp tech.bm-sms.co.jp 人物紹介 キム ダソム(以下、キムPO) エリアプロダクトオーナー 田村恵(以下、田村PO) エリアプロダクトオーナー 原野誉大(以下、原野EN) エンジニア 伊達大晃(以下、伊達EN) エンジニア 福田尚亮 スクラムマスター兼ファシリテーター 貝瀬岳志 全体のスクラムマスター兼本記事の執筆者 組織のアジリティ向上を目指したチーム再編 —— 12 月はクロスファンクショナルチーム(注: プロダクト開発に必要なスキルを保有している、または習得できるチーム)を目指すため、キムさん、原野さんの組織で既存の複数チームをフロントエンドとバックエンド混成になるように再編成したタイミングだったかと思います。まずは、当時の懸念について教えてください 原野EN:私のチームでは既に11月の時点で、フロントエンドエンジニアがバックエンドも担当することになっていました。それは当初の期待通り、やりやすくなったかなと思います。一方、再編成後の新チームでは、複数の文化を持ったチームメンバーが混ざりあうので変化がより大きく、難しい点が出てくるだろうなと思っていました。 キムPO:中長期的な視点では、自律的なクロスファンクショナルチームを作っていくのは実現したいことでしたが、原野さんと同様に、文化の違う2チームが1チームになる時に文化の違いや開発の進め方の違いがどうなるのかが気になっていました。今思えば構造的な問題が原因ですが、チーム再編前はバックエンド開発を先行し、その後別のスプリントでフロントエンド開発が追従するといった進め方を取っていたので、混成チームになったときの具体的な進め方がイメージできませんでした。議論しながら進め方を決めていくなどのチームビルディング期間が必要になると思っていたのですが、当時は大きなリリースを控えていた時期なので、一時的に起こるであろうスピード低下をどのように取り戻していくのかが気がかりでした。そういった中での再編成は、本当に大きなチャレンジだったと思います。 —— うまくいった時のリターンに期待しつつも、大きなリリースの直前に体制を変えていくことによるリスクも大きかったですよね。1 月現在も、「 Done の定義 」の再定義など、新チームでのチームビルディングを実施している最中ではありますが、現時点で見えているチーム再編成の効果についても聞かせてください キムPO:再編後に、混合グループによる複数チームプロダクトバックログリファインメントを実施したことによって、未来への不確実性が一定下げられた実感があります。クロスファンクショナルなフィーチャーチームを目指す過程の中で、当面のプロダクトバックログアイテムに対する全員の解像度を底上げできたことが良かったと思っています。全体に目を向けた影響で、とあるプロダクトバックログアイテムの開発を田村さん・伊達さんたちの組織と分担して進めるきっかけにできたことも大きかったです。 また、うまく行かないことが出てきたときに、元のフロントエンドとバックエンドで別れたチームに戻すという話ではなく、新チームの中で解決すべき課題と捉えている状況も良い点かなと思っています。例えば、フロントエンドの開発タスクが多いという事実に対して、チーム全体のスキルアップを課題として捉え、バックエンドエンジニアがフロントエンドの実装にチャレンジできるような戦略をチーム自身が議論して実行に移しています。実際既に、バックエンドエンジニアがフロントエンドタスクを消化できるようになっているという成果もでているので、チャレンジして良かったなと思っています。 原野EN:もう少し広い範囲で振り返って見ると、LeSSの導入から毎月のように大きな変化が起こり続けていたかなと思っています。スプリントが2週間なので、2スプリント経過して変化に慣れてきた頃に、また大きな変化が起きて、みたいな。ただ、この4か月でプロセスや組織を変化させていくこと自体に慣れてきて、アジリティの高いチームになってきた実感があります。1つ1つの大きな変化はキムさんが中心となって推し進めていたわけですが、うまくいかない可能性も大きい中で、どんどん進めていくところはすごいなと思いながら見ていました。変化に追従するチームも大変ですが、変化を働きかける方はもっと大変だろうなと感じます。 キムPO:ありがとうございます。一方、どんどん変化している状況の中で、各取り組みに対する評価が曖昧になっている点を課題として感じています。最終的にはチームの安定化を目指したいと思っていますが、直近ではプロダクトロードマップに関連する計画と実績の差分、各スプリントにおけるベロシティなどが見るべき指標になるのかなと思っています。 原野EN:話をしていて、この座談会自体が1つ1つの変化に対する見直しのきっかけになっていることに気づきました。 —— 組織の適応性は、 LeSS フレームワーク の中でも重要なポイントとしてあげられていますね。スクラムマスターとして支援に入ってから、変化に対してどう適応していくのかという議論が各所で建設的になされていたことが印象的で、組織としての重要な価値観に通じるところなんだろうなと感じています 将来の展望 —— 最後に、組織やチームに対する今後の期待について一人ずつ聞かせてください 伊達EN:私の組織では、既にバックエンドやフロントエンドなどの技術領域での役割分担が減ってきている実感があります。その先は技術領域というか、プロダクトディスカバリーや品質保証など、エンジニア以外の職種に頼っている領域にも広げて行きたいです。完成の定義を拡張して、価値提供に必要なことはスプリント内で何でもできるような、問題解決力の高いチームになっていけるといいなと思っています。 田村PO:私の組織ではクロスファンクショナルなチーム分割をしたばかりですが、今後はプロダクトマネージャーやプロダクトオーナーが担っている業務、具体的にはプロダクトバックログアイテムの作成などもチームの誰もが担当できる状態にしていけると良いなと思っています。 原野EN:新しいメンバーがチームにジョインしたり、新たなチームが作られたりすることが今後もあると思うので、そこで起こりうる課題に対しても、うまく乗り越えていきたいと思っています。クロスファンクショナルなチームにはなってきましたが、組織全体としてドメインカットでチームが作られているので、そのあたりを解消していくことが今後の課題かなと思っています。あらゆるチームがあらゆるドメインを対応できるような変化が起こると思っているので、その変化に期待しています。 キムPO:私のプロダクトは今後2〜3年後を見据えた時に、まだまだ拡充すべき機能・サービスが控えているので、今よりメンバーが増えていくはずです。現在はクロスファンクショルチームで開発を進めていく過渡期かとは思いますが、メンバーが増えたときに個々のチームを安定させた状態で、どのようにスケールアウトしていくかが次の課題になっていくだろうなと思っています。今できることは引き続きやっていきながら、未来の視点も入れながら、準備を進めていきたいと思ってます。 —— クロスファンクショナルなフィーチャーチームを進める過程で、どんな領域でも学習しながら進めていけるチームになっているので、結果として組織全体のアジリティが向上していくんだろうなと思っています。スクラムマスター一同としても、皆さんの期待を実現できるように、引き続き支援させていただきます。座談会に参加いただきありがとうございました まとめ 計3回に渡って紹介してきたLeSS座談会では、以下のようなトピックを扱いました。 Part1:LeSSの導入から初月まで LeSS導入時の印象や期待 LeSS導入後初月に起きた変化 Part2:LeSS導入後に起きた役割と組織構造の変化 チームの自律性向上のための役割廃止 コンポーネントチームからクロスファンクショナルチームへ Part3:変化を続ける組織と将来の展望 組織のアジリティ向上を目指したチーム再編 将来の展望 短い間にLeSSの導入・プロジェクトリードという役割の廃止・クロスファンクショナルチーム/フィーチャーチームへの再編、といった大きな変化が起こり続けましたが、プロダクト開発の当事者自らが主体となって考え、実行してきたことが伝わったのではないでしょうか。 他方、スクラムマスターやマネージャーは、LeSS導入における 3 つの原則 などを念頭において、当事者への強制は避け、観点を広げるための働きかけや、当事者が必要とする支援を行うよう努めています。LeSSは日本国内においての事例が少ないので、導入を検討している組織の参考になれば幸いです。
アバター
こんにちは!カイポケリニューアルの開発推進チームでエンジニアをしている @_kimuson です。 フロントエンド開発において視覚的リグレッションテスト(Visual Regression Testing、以下 VRT)は欠かせない存在です。 私たちのチームでは長らく Chromatic を活用してきましたが、プロジェクトの成長に伴い、よりスケーラブルでコスト効率の高いソリューションを模索する必要が出てきました。 本記事は 2 部構成の前編として、内製化の決断に至った背景と代替ツールの検討過程を紹介します。 後編では実際の実装プロセスと移行作業の詳細に焦点を当てる予定です。 内製化の決断 🤔 Chromatic の利点 Chromatic は Storybook をベースにした VRT を提供する SaaS です。 簡単なセットアップで優れた開発者体験と直感的なインターフェースを提供しています。 私たちのチームが特に価値を感じていた点は以下の通りです: 最小限のセットアップのみで Storybook をベースにした VRT を動かすことができる VRT のしきい値も効果的に設定されており、特にチューニングせずとも Flaky(不安定な)テストを最小限に抑えられている わかりやすい差分の表示と、Story 単位での変更承認/拒否の柔軟なワークフロー VRT により、安全にフロントエンドを編集できる点 コードレビューの際に変更によって UI がどう変更されるのかが自動でわかる開発者体験 VRT に加えて Storybook がホスティングされ、非エンジニアに再現の難しい状態の UI を共有できる点 Chromatic に大いに助けられてきましたが、プロジェクトの規模拡大に伴い課題も見えてきました。 内製化を検討するきっかけ 💰 最大の課題はコストでした。 我々のチームではスナップショットの総数が月あたり約 13 万スナップショットずつ増加しており、検証開始の時点で合計約 70 万スナップショットに達していました。 Chromatic の課金形態はスナップショット数に対する従量課金であり、スナップショットに対して線形に金額が増えていきます。プロジェクト規模に適したコスト構造を考え、内製化を検討するに至りました。 月辺り 13 万スナップショット増加していることからもわかるように、フロントエンドのコードベースと機能拡大に伴って、この費用は今後も増加が予想されます。 そこで、Chromatic の優れた開発体験をできる限り維持しながら、よりコスト効率の高い代替手段を探ることにしました。 代替ツールの検討 🔍 内製化にあたって重要だったのは、Chromatic が提供していた価値をどう置き換えるかという点です。 代替ツールを検討する前に、まず Chromatic から得ていた主な価値を整理しました。 Chromatic から得ていた価値 💎 Chromatic は単なる VRT ツールにとどまらず、フロントエンドの開発フローおよび品質保証に幅広く価値を提供しています。 特に以下の 3 つの価値が重要でした: リグレッションの検知 UI に意図しない変更が入っていないかを自動的に検知 継続的な品質保証の基盤 開発体験の向上 PR の変更によって UI にどのような影響があるかを視覚的に確認 Story 単位での変更承認/拒否により、コンポーネントごとの細かなレビューが可能 Storybook 共有によるコミュニケーション基盤 デザイナーやプロダクトマネージャーとのコミュニケーションツールとして機能 再現が難しい条件の UI 状態も、Storybook でパラメータを固定して共有可能 コンポーネントの全バリエーションを一覧できるカタログとしての役割 これらの価値をできる限り維持しながら内製化を進める必要がありました。 Storybook のホスティングを代替する 「3. Storybook 共有によるコミュニケーション基盤 」について、Storybook をホスティングできることについては、Storybook 自体は静的な配信に対応しています。 ですので、単に「ブランチごとにビルドをして AWS S3 等のホスティングが行えるサービスでホスティングする」仕組みだけ作れれば良いので、GitHub Actions で AWS S3 にアップロードするワークフローを組むことで対応できる見立てが立ちました。 VRT の実行およびレポート確認を代替する Storycap + reg-suit Storycap と reg-suit の組み合わせは、オープンソースで VRT を実現する広く使われているオプションです。 VRT の実現には、大きく分けて スクリーンショットを撮影する部分 UI の差分を検知する部分 レポートを表示する部分 の要素が必要ですが、Storycap が 1 の撮影部分を、reg-suit が 2 と 3 の差分の検知とレポート部分をカバーします。 実際に既存の Storybook に組み込んでみて挙がった課題点とそれぞれの対応案は以下の通りです: ビューポートサイズ 📱: デフォルトでは正方形に近いサイズで、多くのページでは適切ではなかった 対応: デフォルトのビューポート指定を追加(823 x 1,512) CSS アニメーション 🔄: ローディングアニメーションが diff になる問題 対応: 提供される disableCssAnimation では固定できなかったので、isSnapshot モード時にスピナーのアニメーションを停止する Storybook のデコレータを追加することで対応 Play Function ▶️: Chromatic では自動的に待機していた Play Function の完了を待たない問題 対応: delay 指定または明示的に waitFor を使用 それぞれの課題も個別対応できることが分かり、十分実用に耐えそうだということで確認できました。 また、reg-suit によるレポートも視覚的にわかりやすく、差分の確認方法も複数用意されています。 Lost Pixel Storybook ベースの VRT を実現する他のツールとして、 Lost Pixel も検証しました。 Lost Pixel は reg-suit + Storycap 同様に Storybook のスクリーンショットを撮影し、変更を検知するためのツールです。Platform 版(SaaS)と OSS 版の 2 つの選択肢がありますが、OSS 版を検討しました。 Lost Pixel は前述の要素において 1 と 2 をサポートします。 差分はどうやって把握するのかというと、最新のスクリーンショットをコミットしておき、スクショを更新することで GitHub の PR の UI から確認する思想で作られています。 自分はあまり使ったことはなかったんですが、複数の差分表示方法を GitHub が対応していて変更内容自体はわかりやすく確認が可能でした。 実際に試用した結果、以下のような特徴がわかりました: セットアップの容易さ : 設定が reg-suit 系に比べて「Easy」によっており、ほぼデフォルト設定だけで動作する 安定性 : Chromatic や reg-suit で個別・特殊対応が必要だったケースも、特に追加設定なく安定して動作していた かなり Easy かつ安定した VRT が実現できていて感触はかなり良かったです。 一方、 課題点 も見つかりました。 実行速度が遅く、ローカルマシン(M2 Max 64GB Mac) でスクリーンショットのみで約 9 分 並列化のオプションは提供されるが、sharding のオプションがなく大規模プロジェクトでの実行時間短縮が難しい ほとんどカスタマイズは不要でしたが、Story 単位のオプション制御は弱くドキュメンテーションも限定的でカスタマイズはしづらい レポート機能が提供されず、GitHub の diff に依存する必要がある 技術比較と選定 ⚖️ 上記の検証結果をまとめると以下のようになります: 各ステップにおけるツール比較 スクリーンショットの capture ツール 良い点 悪い点 Storycap 実行時間に難はあるが、並列化および sharding オプションが提供され、スケールに耐える Chromatic よりフレイキー気味で個別対応が必要になりがち。play function 非対応 Lost Pixel (OSS) 安定している 実行時間に難があるかつ sharding できないのでスケールに限界 リグレッション検知・レポート ツール・サービス 差分チェックの体験 reg-suit レポート UI が提供され Chromatic に近く使いやすい体験。Story ごとの Accept/Deny/Comment ができない点は Chromatic に劣る Lost Pixel (OSS) レポートは提供されず、ローカルまたは CI で新しいスクショをコミットし、GitHub の diff で確認する想定 事例はほとんど見かけませんでしたが スクショ部分を Lost Pixel リグレッション検知とレポート部分は reg-suit のような構成も一応取ることができるので、併用する案も含めてそれぞれ選定を行い、 reg-suit + Storycap の構造を取ることに決めました。 理由: スクリーンショットの capture : Lost Pixel も簡単かつ Flaky さが少なくて感触は良かったのですが、実行時間のスケーリングが厳しそうな点で選択できないと判断しました 検証時点でも 1000 以上の Story が存在しており、今後も増えていくことを考えると sharding が不可能な点は致命的でした リグレッション検知・レポート: Chromatic に習熟している開発者の生産性を極力落とさずに移行してもらうためにもレポート画面がある点で reg-suit は魅力的だったため、採用しました Lost Pixel の場合、ワークフローが煩雑になってしまう点もマイナスポイントでした reg-suit + Storycap の構成では、Chromatic と比較すると開発者体験は若干劣るものの、以下の点で優位性がありました: コスト 💰: 大幅な削減が見込める カスタマイズ性 🛠️: ワークフローの各段階をカスタマイズ可能 実行環境の制御 🎮: 自社環境で実行するため、実行ノードのスペックやタイミングを制御可能 一方で、以下のトレードオフが存在します: 開発者体験の低下 : Story ごとの Accept/Deny/Comment ができない 差分確認は GitHub のコメントを使ったやり取りになる 特殊な Story に対するカスタム対応が必要になる場合がある 運用コスト : 初期構築と継続的なメンテナンスが必要 GitHub Actions の実行時間と費用のバランス調整が必要 これらの比較を行い、コスト削減効果と許容できる開発者体験のバランスを考慮し、 Storycap + reg-suit を採用することで決定しました。 やや開発体験の低下はあるものの、十分許容できるラインと判断しました。 まとめ 📝 Chromatic からの移行を検討する過程で、複数の VRT を提供する OSS とアプローチを検証しました。 その結果、コスト削減効果と開発者体験のバランスから、Storycap + reg-suit の組み合わせが最適であるという結論に至りました。 主な決め手となったポイントは以下の通りです: 大幅なコスト削減 : 月額費用の大幅な削減が見込める 許容可能な開発者体験 : 体験は Chromatic には若干劣るものの、主要な機能は維持できる 1-2 を満たしながら現実的な CI の実行時間を維持できる 今回は採用しませんでしたが、組織が小さいタイミングでの Chromatic はほぼ最低限のセットアップで高度な開発体験を提供してくれますし、Lost Pixel (OSS 版) も簡単さ・安定性で優位があり、重視するトレードオフによって良い選択肢だなと思いました。 次回予告 後編では、Storycap + reg-suit を使ったワークフローを実際に構築していく際の工夫した点や移行のプロセスについて紹介する予定です! お楽しみに!
アバター
こんにちは!カイポケリニューアルのサービス提供管理チームでバックエンドのエンジニアをしている清田です。ここ3ヶ月はフロントエンド開発をしています。 この記事ではバックエンドを主戦場とするエンジニアがフロントエンド開発に挑戦して学んだこと、見えてきた風景について紹介します。 (以降、バックエンドを BE 、フロントエンドを FE と略します) また私の個人的な体験ですが、FE 開発に貢献するためどのように学習したのかについても共有します。 BE エンジニアの FE 開発への挑戦、おすすめです! なぜ FE 開発をするようになったのか 私が FE 開発に挑戦するようになった背景には、いくつかの要因がありました。 チーム編成の変化 まず、チーム編成が職能別からユーザーへの価値にフォーカスした編成に変わったことが大きいです。 カイポケのリニューアルプロジェクトでは、 ドメイン毎のサービスで構成されたアーキテクチャで開発を行っています 。 私は居宅介護支援事業所のケアマネジャー向けのケアプラン作成に関するドメインの中で、BE の機能開発を行うチームに属していました。 カイポケのリニューアルプロジェクトの開発チーム全体で LeSS が導入されたことにより、 2024年12月に居宅介護支援の領域では「サービス提供管理チーム」という名称で、デザイン、 FE 、 BE 、QA それぞれの職能に強みを持つメンバーが同じ1つのチームになりました。 (※ 導入理由などについては、 LeSS の導入で変わるマネージャーの役割 に詳しくあります) この編成の狙いの1つには、将来的には希望するメンバーについては職能を横断して別領域に挑戦しながら、チーム全体で提供できるユーザーへの価値を高めていくことも含まれています。 チーム構成の課題 チーム内での FE, BE それぞれを強みとする開発者の人数比率がアンバランスになった(FE:BEの人数比が 1:3 だった)こと、タスク量が FE のものの方が当時は多かったこともあり、FE の開発ができるメンバーを増やす必要がありました。 (現在は他チームからのメンバー移動などもあり人数比率は FE:BE でだいたい 1:1 です) そのため、FE の主力の開発者(以降 FE メンバー)が新機能開発や難易度の高い開発に注力し、 BE メンバーが細かなバグ対応のような難易度の低いタスクや、そもそも GraphQL schema を定義し共有することで連携が必要だったエラーハンドリング系のタスクなどを一気通貫でこなすことになりました。 個人的な挑戦 私自身、 FE 開発に挑戦したいという思いがありました。BE から FE まで一気通貫で開発できるようになりたかったからです。 また、エス・エム・エス入社前は開発言語としては Java メイン、入社後も Kotlin を書いていたので、言語的に TypeScript での開発体験は気になっていました。 加えて React での component をベースにした開発を経験することで、BE の開発で求められる頭の使い方とは違うものを吸収して、ものづくりをする際の考え方の視野を広げたいとも考えていました。 そのため、FE 開発に挑戦することにしました。 足りていない知識は何なのか 今回の FE 開発の挑戦には、担当するプロダクトは変わらないため BE 開発時代に得たドメイン知識はそのまま活用することができました。その上で FE 開発を始める前に自分に足りていない知識や経験は次のものでした。 FE の技術スタックの複雑さ(清田個人の知識の積み上げがないという意味です) 開発環境が異なる(=Visual Studio Code を使用する)ことによる負荷 FE の技術スタックの複雑さ 私の FE のスキル感は、2021年ごろに JavaScript Primer と 『りあクト! TypeScriptで始めるつらくないReact開発 第3.1版』 を一周やったことがあるくらいで、業務ではしっかりと FE に触れたことがありませんでした。 そのため、 HTML、 CSS の基礎と TypeScript の書き方と Next.js の概要についてキャッチアップが必要と考えました。 開発環境が異なる(=Visual Studio Code を使用する)ことによる負荷 これまでの BE 開発の経験から IntelliJ をずっと使っていたため FE 開発でも IntelliJ を使うという選択肢もありました。 ただし今回は以下の理由から Visual Studio Code(以降 VSCode) で開発することにしました。 FE 開発では VSCode が一番使われていること 2024 年の JavaScript と TypeScript のトレンド: 開発者エコシステムアンケートのインサイト FE メンバーはみな VSCode を使っており気軽に知見を聞けること 『達人プログラマー(第2版)』 の「第3章 基本的なツール」の 「職人のように常に道具を増やすことを心がけてください。」に従って開発時のインターフェースとしての道具も増やしてみたかったため どうやってキャッチアップしたか 個人的な体験ですが、BE エンジニアが FE 開発に挑戦した際にどのようにキャッチアップしたかを共有できればと思います! (もちろん現状でキャッチアップできたとは思っておらず、以下に挙げるものは今も継続的に取り組んでいることです!) 技術スタックを知る まずは、プロダクト開発をするにあたっての前提として必要な HTML、 CSS、 TypeScript、 React、 Next.js の基本的な知識について以下の内容を手を動かしてキャッチアップしました。 HTML、CSS については、MDN ドキュメントの 入門モジュール と コア学習モジュール の中でプロジェクトの開発で知識として必要そうな箇所 TypeScript については、 『プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで』 で基本的な文法と型の種類について React、Next.js についてはチュートリアル( React Foundations 、 App Router )を実施 次にプロジェクトで使われているライブラリについて先に軽く調べておきました。 ただこちらはそれぞれを動かして試す時間はないため、導入されている意図を予測し、 〜をつかうことで〜が嬉しい!? みたいなフォーマットで自分なりに導入理由を想像してメモを残すに留めました。 VSCode ホームポジションから動かずにソースコードを行き来する 個人的な好みの問題なのですが、ソースコード内を移動する時にホームポジションから動かずに操作したい派です。 既に実装がある程度進んでいるプロダクトの開発時ではソースコードを読む時間が一定あります。 一貫性を持った実装にするために参考にするべき実装を探す時や、 component の階層が深くなっていった際の定義の移動を、思考の流れを止めずにホームポジションで行えることは既存のコードを理解するためにとても重要です。 コードリーディングに着目してショートカットを紹介している記事 【VSCode】コードリーディング特化のショートカット集 が本当に参考になりました! あとは IntelliJ ではショートカットを覚えるほどではないものについては Find Actions を多用する派なので、VSCode でも Command Palette は多用しています! モブプロでの学習 最初の開発については、FE メンバーとFEに挑戦するメンバーでモブプロで進めました。 FE の実装においてはどのようにソースコードを追うのか ディレクトリ構造 TypeScript のちょっとした文法 テストの書き方(どの粒度でどのように書くのか) などの疑問点を同期的に質問しながら作業することで開発の流れや実践的なスキルを学ぶことができました。 なお、最初の開発以降は、初めて取り組む実装の際は必要に応じて FE メンバーに協力をお願いしてペアプロやモブプロで開発することもあります。 プロダクト開発を通じた学習 実際にプロダクト開発することは何よりの学びになりました。 修正箇所の Figma のデザインやアプリケーションの操作から、コードを書くべき場所に当たりをつけてソースコードを読んでいく過程で component を組み合わせて画面が作られていることを実感しました。 個人的に FE 開発に限らず意識していることですが、少しずつ違う性質の実装タスクに取り組むことで担当できる領域を広げていきました。 そして、プロダクト開発を通じて以下のようなことを段階的に学んでいきました。 Figma から情報を読み取って実装に反映する CSS の box model の style の調整について(margin、padding の使い方) Figma の Dev Mode で確認して実装したものと DevTools で対象の element を選択して Computed したものを見比べて style が正しいか確認する Testing Trophy の考えに従い、 component 単位でテストを書き、ユーザの動作を保証することについて エラーを表現する component の新規追加 component の props で ReactNode を渡すようにして JSX で柔軟にエラーに関する情報を渡す なによりこれらは FE メンバーに PR にて提案や指摘をいただいて学べたことです。ありがとうございます! FE メンバーの PR をみる バックログリファインメントに参加し実装背景や実装方法の方針がわかっているタスクについては、FE メンバーの PR を覗いて、TypeScript らしい書き方や自分では思いつかない実装方法や考え方について学ばせていただきました! FE 開発をやって良かったこと BE エンジニアが FE 開発に挑戦して学んだこと、見えてきた風景について紹介します。 システムの使われ方をより明確にイメージできるようになった FE 開発でユーザーに近い部分を実装したため、ユーザーが実際にカイポケを使用する時のことがよりイメージできるようになりました。 FE のタスクとしてエラー時の UI や表示するメッセージを考える時だけでなく、BE で API (GraphQL server の実装)を追加する際にも、クライアントでどのようにそれが使われるのかを以前よりも解像度高く考えることができるようになりました。 デザインへの興味がでてきた FE 開発の中で学んだこととして、 Figma の Dev Mode で確認して実装したものと DevTools で対象の element を選択して Computed したものを見比べて style が正しいか確認する をあげたのですが、実際は多くの場合は Figma と社内 UI ライブラリで提供されている component の名前が一致しており、デフォルトの値が指定されているので細かな調整をすることは少なかったです。 これはデザインシステムを整備いただいていたからのようです! (詳しくは デザイナーとエンジニアで育てる組織の共通言語としてのデザインシステム ) この驚きを機に UI の世界の共通言語やそれを表現する component に興味が出てきて、いろんなライブラリの component を眺めたり、他社のデザインシステムをカタログ感覚で見るようになりました〜 shadcn/ui 、 Tailwind CSS 、 Chakra UI の提供する component を見たり、プライベートで shadcn/ui を使用して画面を作ってみたりしています! FE 系の話題について目に留まるようになった 日々ちょっとした時間にチェックしている、 はてなブックマークのテクノロジーの人気エントリー や Zenn の Trending で流れてくる FE 系の話題について、表面的ですが何について書かれているのかわかるようになりました!プロダクト開発をした経験により見える世界が広がりました。 VSCode での開発に慣れた 道具を増やすことを意識して VSCode を使い始めたのが功を奏して、 Cursor を使用したり、最近盛り上がっている Cline を動かしてみたりといった新しい開発体験をプライベートの開発でカジュアルに試せるようになってきました。 (変わらず IntelliJ のことも好きなので JetBrains の Junie も楽しみにしています!) また、VSCode を不自由なく扱えるようになったことで他の言語の開発やソースコードリーディングに対するハードルも下がりました! ソースコードリーディングの力がついた 画面の表示や操作から仮説を立ててコードを追っていき修正箇所を見つける、という経験を通じてソースコードリーティングの力がつきました。 ユーザの操作 → API 呼び出し(FE の実装) → BE の実装 まで一気通貫でソースコードを追って問題を見つけられるようになりました。 BE の技術の幅も広がった プロダクト開発とは関係がなくなるのですが、 TypeScript と VSCode での開発に慣れたのでプライベートで Hono を使用した実装の素振りもしました。 ( RPC の開発者体験がとても気持ちよかったです) (広く浅くにはなりますが)別言語や別の思想の Framework を触ることで、自分のスキルセットの中でメインで使っている技術の書き方にも活かせたり、扱える技術の幅を広げることができたのでよかったです。 FE 開発に挑戦したことでチーム開発に貢献できたこと これまでに BE エンジニアが FE 開発に挑戦したことによる個人的な収穫について記載しました。 ここではチーム全体で提供できるユーザーへの価値を高めていくために貢献できたことについて紹介します。 FE メンバー(FE の主力の開発者)が実装難易度の高いタスクや新機能の開発に注力できるようになった BE メンバーが、細かなバグ対応やエラーハンドリングのタスクを一気通貫で実装できるようになったことで、FE メンバーがよりインパクトの大きい開発に注力できるようになりました。 (今後は BE メンバーも徐々に実装の難易度が高いものにも挑戦していく予定です!) なお、最初の2週間はモブプロの予定をたくさん入れていただき、BE メンバーが自走するまで手厚くご協力いただきました。今でも詰まってしまった際にサポートいただいています。ありがとうございます! バックログリファインメントでの BE/FE の対応状況を整理しやすくなった FE のタスクについてバックログリファインメントを行う際に BE メンバーがいることで、 BE の対応状況や使用する API について共有することができるため、タスクの見積もりの確度を高めるのに貢献できました。 FE、BE どちらもローカル時の困りごとの解消を手伝えるようになった BE では単体テストや Subcutaneous Test で動作を保証しながら開発をしているため、 これまでは FE をローカルで起動していませんでした。 (ユーザの動作は dev 環境で確認していました) FE 開発を機に初めてローカル起動するようにしたことで、BE の起動方法の知見と紐づけて以下のようなちょっとした手伝いができるようになりました。 特定の branch で BE を起動して動作確認する方法をドキュメント化して共有 ローカルで BE のデータセットアップが不足していてエラーになるのを解消する 最後に FE 開発は BE エンジニアにとって新たな世界が広がり、スキルセットを拡げる絶好の機会です。 また BE と FE の垣根を越えることでチーム内での協力体制を強化しつつ、プロダクト開発全体の効率化に貢献することもできるはずです。 この記事が FE 開発にも興味がある BE エンジニアの方にとって役に立てれば何よりです。以上です!
アバター
キャリア事業部のエンジニアの田実です! 3/21〜23に開催されたPHPerKaigi 2025に協賛&参加&登壇したのでそのご報告になります! phperkaigi.jp シルバースポンサーとして協賛していました! エス・エム・エスはPHPerKaigi 2025にシルバースポンサーとして協賛しました! キャリア事業部ではエンジニアを募集しております! PHP/Laravelも利用しておりますので興味がある方は是非お話ししましょう!! ソフトウェアエンジニア カジュアル面談(PM/EM/SRE/QAも歓迎) / 株式会社エス・エム・エス 登壇: Alpine.js を活用した
Laravel MPA フロントエンド最適化戦略 speakerdeck.com Alpine.js というJavaScriptライブラリについて紹介させていただきました。Alpine.jsは前職も現職も導入経験がありオススメな技術の一つなのですが、国内ではイマイチ盛り上がっておらず是非紹介したいなと思い今回の登壇に至りました。 本発表を聞いてAlpine.jsを使ってみたいと思った方が増えてくれたら嬉しいですし、皆様の技術選定に少しでもお役に立てれば幸いです! 今回は時間の都合上カットしましたが、Viteによるビルド、Vitestによるテスト、TypeScriptによる型導入、Biomeによるフォーマット・Lint適用、Sentryによるエラー検知などMPAのフロントエンド改善を現在進行系でバシバシやっていますので、こちらもどこかで機会があれば発表できると良いなと思っています。 ちなみに、今回の登壇準備にあたり生成AIを活用しました。具体的にはGeminiやChatGPTを活用し以下の内容の調査・壁打ちをしました。 スライド構成 CfPの内容からスライド構成を出してもらい、観点漏れを指摘してもらいました。 発表内容 Alpine.jsによるUIコンポーネントテストの方法を教えてもらいました。これは検索してもなかなか出てこなくて自分の当時の知識では思いつきもしなかったです…。 技術のPros/Consにおいて、自分が考えている以外の観点のものが無いかを確認しました。 スライドや構成検討に毎回頭を悩ませているのですが、生成AIを使うと気軽に壁打ちできるためいつもより捗った気がします。技術調査も生成AIにより効率的に理解することができました。特にAlpine.jsのような有識者があまりいない技術領域の調査においては大変心強かったです。 参加した感想 php-srcのコアな内容や以前の職場での取り組みを聞けて技術的にも仕事的にも非常に刺激を受けました。登壇が終わって一息つくはずが他の人の発表を聞いたり話していたら次の登壇への活力が湧いてくるのは何故でしょうね…?w また、技術イベントの懇親会への参加は5年ぶりだったのですが「あの有名なライブラリの作者さん!」や「めっちゃ面白いLTしてた方!」や「部署違いで全然話したことない同僚!」といった方々と楽しくお話できたのは貴重な機会でしたし、対面で会って話すことの良さを改めて感じました。 最後になりますが、スタッフの皆様、素晴らしいカンファレンスをありがとうございました! 登壇者・参加者の方もお疲れ様でした!!
アバター
エス・エム・エス BPR推進部 キャリア横断開発グループ データ基盤チームの手塚と申します。2024年9月に当社に入社し、早くも半年が経過しました。 この記事では、私自身が実際に感じたことを「仕事の進め方」と「文化」の2つの観点からご紹介します。SIer・SES企業から転職を検討している方、またはエス・エム・エスに興味をお持ちの方にも、参考になる情報をお届けできれば幸いです。 経歴 前職ではSESエンジニアとして、BI画面開発やデータ連携(ETL)の開発業務に携わっておりました。SES(System Engineering Service)とは、契約期間に基づき、クライアント企業に対してエンジニアの技術力や専門スキルを提供するサービスです。具体的な働き方としては、お客様の要望や課題をヒアリングし、それを基にシステム開発を行い、納品、運用、保守まで一貫して担当していました。 SESと自社開発(エス・エム・エス)の違い 仕事の進め方 仕事としての関わる範囲・人 まず、入社して感じたことはエンジニアとしての役割が非常に広い点です。 私の所属するデータ基盤チームでは、「社内のデータ活用の推進」を目的の一つとして、日々多種多様な案件に対応しています。例えば、半日で対応可能な簡単な案件から、1年以上を要する大規模プロジェクトまで、案件の規模は様々です。 また、キャリア横断開発グループに所属していることから、担当する案件も単一のサービスに留まらず、エス・エム・エスが展開する多岐にわたるサービス群に及びます。そのため、社内外の多くの関係者と連携しながら業務を進める必要があり、関係者との調整や意思決定に苦労する場面も少なくありません。ですが、その分、自らの仕事が会社全体の事業に貢献しているという当事者意識と、大きなやりがいを感じることができます。 (オレンジ箇所がキャリア横断開発グループとして対応しているサービス領域) 一方、前職のSESでの働き方は、プロジェクト全体のごく一部分のみを担当することが多く、担当領域が限定されていました。そのため、関わる社内外の関係者や部署も固定化され、プロジェクトによっては、リーダー層の方のみがお客様と直接コミュニケーションを取り、現場のエンジニアは、プロジェクト開始時と終了時の挨拶以外、お客様と直接会話する機会がほとんどないケースもありました。 開発手法・仕様の決まり方 開発手法も異なっていました。前職ではウォーターフォール開発が主流で、要件定義→設計→開発→テスト→リリースと必ず前工程が完了してから次の工程に進んでいました。 対して、データ基盤チームではアジャイル開発を採用しており、一連の開発工程を短期間で繰り返します。ウォーターフォール開発は、経験の浅いエンジニアにとっては、各工程でやるべきことが明確で進めやすいというメリットがあると感じていました。しかし、開発に時間を要するため、成果物がなかなか目に見える形にならない点や、リリース直前にお客様からのフィードバックによって大幅な手戻りが発生し、モチベーション維持が困難になる点が課題でした。 アジャイル開発では機能単位のリリースで改善が実感でき、ユーザ側にも成果物の共有がしやすく、反応が感じられる点が非常に良いなと感じてます。 また、仕様の決定プロセスも大きく異なります。前職では、仕様は基本的にクライアントからの要求に基づいて決定されるため、私たちから積極的に提案を行う機会は限られていました。しかしながら、エス・エム・エスのような自社開発企業では依頼者が身内なこともあり、直接業務担当者とコミュニケーションを取りやすく、仕様についても柔軟に決定することが可能です。データ連携の仕様についてもエンジニアから提案する場面をよく見かけます。 キャリア横断グループと前職の仕事の進め方の違いをまとめると以下の表のような感じです。 キャリア横断グループ SES(私の前職) 関わる範囲 複数サービス プロジェクトの一部 関わる人 複数の担当者 固定の担当者 開発手法 アジャイル ウォーターフォール 仕様の決まり方 柔軟に決定 (こちらからも提案) 基本的にクライアントからの要求で決定 文化 企業文化として重要視していること 企業文化についても、前職とエス・エム・エスとでは大きな違いがあると感じています。 まず、最も大きな違いとして感じたのは、業務において重要視していること(目的)です。前職のSES企業では、SIer・SES企業ではよくあることかもしれませんが、「開発すること」自体が目的化しており、お客様からの要望に「いかに応えるか」に焦点が当てられていました。また、SES契約という契約期間に制約がある働き方であったことも影響し、プロジェクトに関わるフェーズによっては、プロジェクトの成功よりも「納品すること」が目的となり、お客様がそもそもなぜシステム開発を依頼したのか、という根本的な課題にまで目を向けることが難しかったと感じる場面もありました。 エス・エム・エスでは、目の前の案件に対し、本質的な解決を目指す姿勢が強く感じられます。例えば、MTGでエンジニアが「この課題は、必ずしもシステム開発をしなくても、スプレッドシートの機能だけで解決できそうですね」と発言し、実際に開発せずに課題解決を目指す場面がありました。その時は、非常に感銘を受けました。 私の所属するBPR推進部のミッションは、「成長と変化を促進するビジネス基盤を構築することで、価値提供先の本来業務への集中を実現し、会社と事業の成長に貢献する」ことです。そのため、開発という手段に固執せず、ユーザー自身で解決できる課題は、その方向でサポートするという姿勢を目の当たりにし、前職との文化の違いを強く感じました。 前職では、お客様の要望によって仕様が決まる場面が多く、その要望に対し「既に決まっていることなので」と、半ば思考停止の状態で業務を進めざるを得ないこともありました。(いつしか自分自身もその状況に慣れてしまい、このままではいけないと感じたのが、転職を考えたきっかけの一つです。) 社内コミュニケーション 社内コミュニケーションの質に大きな違いを感じています。 前職では、Teamsが導入されていたものの、活用方法は業務連絡が中心で、雑談などのコミュニケーションはほとんどありませんでした。原因として、エンジニアが別々のプロジェクトに派遣される働き方のため、コミュニケーションが同じプロジェクトのメンバーに限定されていたことが挙げられます。また、他のメンバーの業務内容やコミュニケーションは、上長クラスでなければ把握できない状況でした。 そのため、プロジェクトは異なっていても同様のツールを使用しているケースがあるにも関わらず、情報共有がスムーズにいかないことがありました。社内全体として、勉強会や共有会などの活発な情報交換の場を設けづらい環境だったと、今振り返ると思います。 一方、キャリア横断グループのエンジニア内では、雑談から仕事の相談まで、活発なコミュニケーションが行われています。Slackのオープンチャンネルを通じて異なる部署のやり取りを知ることができ、他部署のメンバーにも気軽に質問できる場面が多く見られます。 また、データ基盤チーム内のコミュニケーションも活発です。朝会の「100の質問」や、レトロスペクティブ、勉強会など、定期的な共有の場が設けられています。そのため、他のメンバーの業務内容が見えやすく、情報共有が非常に円滑だと感じています。 私自身、入社して4か月後に他部署の人を交えて読書会の開催ができました。このような活動ができたのも、キャリア横断グループの活発なコミュニケーション文化のおかげだと感じています。 キャリア横断グループと前職の文化の違いをまとめると以下の表のような感じです。 キャリア横断グループ SES(私の前職) 重要視していること 課題解決にフォーカス クライアントの要望にフォーカス コミュニケーションレベル 雑談~仕事の相談まで 基本的に業務連絡のみ コミュニケーションの頻度 複数回/週 勉強会も定期的に開催 不定期 さいごに 自社開発企業とSESとの違いを仕事の進め方や文化という観点から違いを述べさせていただきました。個人的に感じた最も大きなギャップは、重要視していることが「課題解決」であるのか「お客様の要望」であるのかです。課題を解決できれば手法にこだわらない姿勢は自社開発企業に合っている方だと感じますし、エス・エム・エスには楽しめる環境が揃っていると思います! また、エス・エム・エスは新しいメンバーを募集しています。 私達データ基盤チームでは、データ基盤の運用から、データパイプラインの開発、データマートやダッシュボードの開発、AIを用いたソリューションの提供など様々な業務を通して事業を支援しています。これまでの取り組みは別記事でも発信しておりますので、以下ページもご覧いただけると幸いです。 tech.bm-sms.co.jp tech.bm-sms.co.jp tech.bm-sms.co.jp エス・エム・エスの事業に携わってみたい方、BPR推進部へ興味のある方は、ぜひこちらのページものぞいてみてください。 open.talentio.com
アバター
合同会社makigai(マキガイ) の貝瀬です。2024年6月からスクラムマスターとして、介護/障害福祉事業者向け経営支援サービス「カイポケ」に関わる組織やプロセスの改善を支援しています。 カイポケリニューアルプロジェクトでは、LeSS(Large Scale Scrum:大規模スクラム)を導入しています。本記事では2025年1月に実施した座談会の続編(Part2)をご紹介します。 Part1については以下の記事をご参照ください。 tech.bm-sms.co.jp 人物紹介 キム ダソム(以下、キムPO) エリアプロダクトオーナー 田村 恵(以下、田村PO) エリアプロダクトオーナー 原野 誉大(以下、原野EN) エンジニア 伊達 大晃(以下、伊達EN) エンジニア 福田 尚亮 スクラムマスター兼ファシリテーター 貝瀬 岳志 全体のスクラムマスター兼本記事の執筆者 チームの自律性向上のための役割廃止 —— 10月にはマネージャー酒井さんから、プロジェクトリードを廃止するという働きかけがありました。プロジェクトリードはLeSS導入以前に、「チームを跨いだコミュニケーションでお見合いが発生することを避けるため、また、マネージャーやプロダクトオーナーの負荷を分散するために定義した役割」でした。自律的な クロスファンクショナルチーム (注: プロダクト開発に必要なスキルを保有している、または習得できるチーム)を目指すことが目的でこの役割を廃止することになりましたが、当時どのような印象や期待があったのかを聞かせてください。 キムPO:長期的な目標から見て、ワンチームで取り組んでいくことを目的に役割を減らすというのはポジティブに感じていました。反面、これまではプロジェクトリードがチームとの窓口を担ってくれていたので、当面は結構カオスになるのではないかという懸念もあり、期待半分・不安半分といった印象でした。 田村PO:私もほぼ同じ印象でしたね。これまでだと、プロジェクトリードにとりあえず依頼しておけばいい感じにやってくれていたのですが、チーム全体に投げかけたときにボールがちゃんと拾われるかどうかという不安は大きかったと思います。中長期で目指していく姿を考えればこのタイミングで廃止しておくべき、ということも理解していたのでネガティブではなかったものの、めっちゃ不安でしたね。 伊達EN:私は田村さん管轄のプロダクトを担当しているチームですが、すでにプロジェクトリードの役割が薄れてきていたので、そこまで何かが大きく変わることはないだろうと思っていました。酒井さんの働きかけより前から、個人というよりチームとして仕事を進めていたので、不安は特に感じていませんでした。 原野EN:9月ごろにミーティングが増えたなと思っていましたが、会話の内容は、チーム分割に関するものだったり、リリースまでのスコープに関するものだったので、プロジェクトリードの役割は想定よりも重い役割に変わっていった印象でした。元々のプロジェクトリードは当番制でも良いくらいの薄い役割で、チームの全責任を担うような重い役割ではなかった認識だったため、その役割をなくしていくことにポジティブでした。個人的な意見であってもチームの代表としての意見として捉えられる可能性があったので、チームの合意をとった方がいいかなとか、悩みながら発言していた記憶もあります。ただ、プロダクトマネージャーやプロダクトオーナーの立場からすれば、プロジェクトリードを廃止することには不安があるんだろうなとも思っていました。 キムPO:スプリントプランニングの1部でも、私からの質問に対してプロジェクトリードの方が回答してくれることが多いので、チーム全体のことを把握しているんだろうなという前提でコミュニケーションを取っていました。それがチーム全体に窓口が広がることで、時間がかかるのではないか、責任の所在が曖昧になるのではないか、といった不安がありました。 原野EN:キムさんのいうような問題が起きて、また元に戻るんじゃないかという懸念もありました。長期的には賛成でしたが、いきなりガッと変化できることでもないので、短期的にはやり方考えないとね、という気持ちが強かったです。 —— 10月から変化が始まって、責任の所在が曖昧にならないか、必要以上に時間がかからないかといった懸念があったかと思いますが、現時点では当時感じていた懸念に対してはどういった状況でしょうか。 原野EN:各チームで代表をローテーションするような折衷案を試したり、いい感じの塩梅を探していく形を取っていった結果、懸念していたような問題は起きなかったと思っています。また、自分自身のGitHubのコミットグラフをみてみたんですが、10月くらいからコミットが増えたなという結果になっていました。そういう意味では、コードを書く時間がかなり増えて、ミーティングが結構減ったなとも思います。 キムPO:私も当時の懸念に関する課題は、顕在化せずにここまで来ていると思います。例えばSlackではチーム宛にメンションしていますが、ボールが落ちたりスルーされることもなく、どなたか必ず回答してくれているので今は安心感があります。ただ気持ち的には、こんなに広範囲でメンションしちゃっていいのかな、ゾーンに入っている時に邪魔しちゃ悪いかな、みたいなことは感じています。気にせずにやっちゃっていますが(笑)。 —— エンジニアのお二人からみて、チーム宛のメンションが飛んでくることへの悪影響や懸念はあったんでしょうか。 原野EN:自分は元々気にならないタイプですし、そもそも変化の前から自分宛にメンションが来ていた状況だったので感覚は変わっていないですね。 伊達EN:同じく気にならないタイプですが、特定の誰かに依存しすぎていること自体が良くないと思っていたので、チームに投げかけてもらった方が当事者意識も出てきますし、むしろその方がポジティブだなと思っています。 原野EN:そうですね、自分は普段から全部知っておきたいというか、気になってSlackを堀り漁っているくらいなので、メンションが飛んできた方がむしろ楽だなとも思います。 —— ちょうど私もスクラムマスターとして支援に入ったタイミングでしたが、責任の所在やコミュニケーションに関する部分は、チームの皆さん自らが課題として捉えられていることを感じていました。自分たちでやり方を決めるところから活発に議論されていて、実行に移していたことが印象的でした。当事者意識という言葉が出ましたが、従来から当事者意識の高い方が多い組織なんだろうなと感じています。10月に関して他のトピックはありますか? 原野EN:9月の段階ではチーム編成など組織に関するトピックがあるとプロジェクトリードが巻き込まれていましたが、徐々にその役割がマネージャーに移っていったのかなと思います。 —— ちょうどこの時期に、マネージャーの酒井さんからLeSSにおける マネージャーの役割に関する課題提起 をされていましたね。 コンポーネントチームからクロスファンクショナルチームへ —— 11月に入ったタイミングでも、大きな変化があったかと思います。キムさん、原野さんたちの組織ではLeSS導入以前、バックエンドとフロントエンドが別々のチームで分業していましたが、フロントエンドチームがバックエンドタスクを学習しながら取り扱い始めた時期だったかと思います。大きな問題もなく取り扱えていた印象ですが、何か工夫した点はあったんでしょうか? 原野EN:フロントエンドチームがバックエンドタスクとして最初に扱ったのは、既存のコードに対して細かい修正で済むような内容でした。まずはバックエンドエンジニアも交えたモブプロで環境構築して、後はまあひとまずやってみようぜ、というくらいの気軽なノリで始めた記憶があります。私が前職でKotlinを扱ったこともあったので、個人的にもなんとかなるのではないかと思っていました。分業していた時は、ここから先はバックエンドなので自分たちフロントエンドチームはここまでで・・といった遠慮や線引きの意識から、気まずさを感じていたので、自分たちが一貫してコントロールできるように変化することは、チームとしてポジティブだったかと思います。 キムPO:フロントエンドチームはまさに期待していた通りの変化が起きたかなという印象です。当時扱っていたプロダクトバックログアイテムは不確実性が低いものでもあったので、移行がスムーズにいったのかなと思います。結果として、他のチームもクロスファンクショナルチームにしていきたいということを考えるきっかけにもなりました。 —— 11月の変化としてもう一つ、田村さん、伊達さんの組織ではチーム分割の検討がされていました。当時の狙いとして、コミュニケーションコストの低減とチームが取り扱う領域の変化への対応があったようです。分割するときに気にした観点や、最終的にどのように意思決定したのかを聞かせてください。 田村PO:チームの人数が増えてきたことによるコミュニケーションの取りずらさとコミュニケーションコストの増加がきっかけで、チーム分割を検討し始めました。さらにチームが扱うドメインも増えていくことが見えていたので、当初はドメインに対してチームを割り当てて分割する方法を考えていました。一方その分割の方法では、元々フロントエンドエンジニアの人数が少なかったのでうまく分割できるのかという不安もありました。そういった事情があり、酒井さんと貝瀬さんにどういうチームの分割の仕方が良いのかというところから相談していたのですが、最終的にはドメインに紐づかない2チームに分割するという形に落ち着きました。各チームが取り扱うドメインが複数になるので、「ドメイン知識のキャッチアップが大変になるのでは?」といったところが気になりましたが、チームが1つだった時からやっていたことではあったので、悩みながらも意思決定しました。チーム分割は10月頃から考え始めて、分割後のチーム編成が決まったのは12月頃だったかと思います。チーム編成は全員参加のワークショップで決めたのですが、その取り組みは非常に良かったですね。 伊達EN:当時は「フロントエンドエンジニア」「バックエンドエンジニア」という職種で入社したメンバーが多かったのですが、フロントエンドエンジニアが少ない状況の中で、適切にチームが分割できるのかという不安はありました。田村さんと同じように、今後扱うドメインが増えていったときに適切に対応できるかという点が特に気になっていたところです。 —— 1月からは分割後のチーム活動が始まっているかと思いますが、結果的に当時の懸念は解消されているでしょうか?もしくは解消されていないでしょうか? 田村PO:まだ動き始めたばかり *1 なので変化が見えきっていないですし、課題はこれから出てくるかもしれないのですが、先ほどもお話したチーム分割のワークショップができたこと自体、非常に良かったと思っています。個々人のスキルを全員で見える化して、どういうふうに組み合わせていけばフィーチャーチームになれるのか?個々人のスキルを伸ばしたり補完し合うにはどうすべきなのか?といった会話をしながら、メンバー全員でチーム編成を決めていけていけたのが本当に良かったです。チームの名前をメンバー自身で決めたのも良かったですね。今後については、チーム単位のスクラムイベントの他にチーム横断の LeSSイベント もやっていくことになるので、チーム横断でも補完しあえる部分が出てくることを期待しています。 伊達EN:チーム分割のワークショップは本当に良かったですね。新チームでの活動は1月から始まったばかりですが、スキルを可視化してお互いへの期待も話し合えたことで、事実、フロントエンドエンジニアとして入社した方がバックエンドのKotlinをキャッチアップし始めていたりします。それ以前は個人的に、「フロントエンドエンジニアとして入社された方にバックエンドの仕事を期待していいのか?」みたいな懸念を感じていました。ワークショップを通じて個々人の得意領域は尊重しつつも、より価値提供・課題解決にフォーカスしていけそうな動きが見え始めているのですごくポジティブな印象を持っていますね。ドメインが増えた時に期待通りに適応できるかというのはこれからですね。 原野EN:伊達さんがフロントエンドエンジニアにバックエンドのことを期待していいのか?という話をされるのは非常に面白いですね。 伊達EN:私はフロントエンドエンジニアとして入社したんですけど、昨年の6月くらいに当時所属していたチームの人数が一時的に減ったことがきっかけで、今はフロントエンドもバックエンドも両方やっているという感じなんですよね。 原野EN:伊達さんは、「自分ができているんだからみんなできたっていいでしょ?」というスタンスでいっても面白かったんじゃないかと思いますが(笑) 伊達EN:もしかすると、私の動きを見てくれていたので、他のチームメンバーも近い動きをしてくれたのかもしれないですね(笑) —— 分割後のチーム名は職種やドメインを使わずに、チームメンバーがアイデアを出し合って決めたということを聞きましたが、2チームともすごく個性的な名前でいいなって思いました。では最後に、12月に起きた変化に関しても聞いていきたいと思います。 まとめ LeSS座談会Part1に引き続き、Part2では導入後に起きた役割や組織構造の変化を紹介しました。座談会の紹介記事はPart3で最後になります。引き続き公開をお待ちください。 *1 : 座談会を実施したのが一月中旬
アバター
こんにちは、鄧 皓亢(でん はおかん)です。カイポケリニューアルプロジェクトのアーキテクト兼PdM(プロダクトマネージャー)としてエス・エム・エスに2024年に入社しました。 もともとはバイオ系の研究をしていましたが、「より早く価値を提供できる仕事がしたい」という思いからデータサイエンティストにキャリアチェンジしました。そこから飲食店向けのSaaS開発、CTO経験を経て、データ分析・データ基盤構築の知見を活かし、現在のポジションに至ります。 キャリアの変遷──データとプロダクトの融合へ 最初はバイオ分野の研究をやっていましたが、研究の成果が形になるまでの時間が長いことに課題を感じ、より早いリリースサイクルを求めて飲食店メディアのデータサイエンティストとしてキャリアチェンジしました。 飲食店メディア自体は楽しいですが、需要と供給のマッチングと言いつつ本質的には一部ポピュラーな店舗の在庫がスケーラビリティのネックになりがちでした。一般的にはポピュラーではない店舗の集客をいかに改善する話になりがちですが、個人的に面白いと感じたのはポピュラーな店舗でもその席在庫の管理方法によって無駄にネット予約分の在庫に制限をかけている場合があり、それ自体は管理方法やオペレーション改善によって改善できる部分があると感じました。 そこから、より顧客の課題にフォーカスするために飲食店むけの予約管理とネット予約をSaaSとして提供しているスタートアップに転職して自分で営業・カスタマーサポート・i18nをしつつ海外事業の立ち上げに関わっていました。 その後、当時CTOだった増井さん( masuidrive )に誘われて東京本社勤務となり、Salesforce導入・データ分析・データパイプライン構築・新規事業立ち上げ・システム設計など、プロダクトとデータの両面から事業を支える役割を担うようになりました。最終的にはCTOとして活動し、組織全体の技術戦略にも関わることになりました。 エス・エム・エスとの出会い──人と文化に惹かれて エス・エム・エスとの出会いは、田辺さん( @sunaot )から声をかけてもらったことがきっかけでした。その後、三浦さんとお話しし、最初は業務委託としてデータプラットフォームチームの立ち上げに関わることに。 立ち上げの経緯は以下をご覧ください。 tech.bm-sms.co.jp 業務委託として関わりながら、データ基盤の整備を進める中で、単なる技術的な課題解決だけでなく、組織の文化や働く人たちの姿勢に強く魅力を感じるようになりました。 僕が今把握している範囲では上場企業のステレオタイプみたいなお堅いイメージは全くなく、業務委託の期間も含めると一年半以上関わってきましたが、現状維持バイアスの塊みたいなものも全く感じませんでした。 スキル的にも優秀な方が多く、個人的にはどうやってこのようなメンバーを集めてきたのか、どうやってこのような文化を定着させたのかに興味を持っており、仕事の合間で深く掘り下げてみようと思いました。こうした環境に惹かれ、最終的に正社員としてエス・エム・エスにジョインすることを決めました。 執筆時点での個人的な仮説ですが、歴史的にカイポケという大ヒットサービスがあり、その設計やスケーラビリティの課題を解決するために今のカイポケリニューアルチームが組織されたので課題解決と現状に囚われない文化が定着したのではないかと考えてます。もしこの仮説が本当だったらリファクタリングはシステムだけではなく、組織や文化に対しても良い影響があることになるので、今まで一部の企業でリファクタリングを忌避していた価値観も見直す必要があるのかなと思います。 現在の役割──カイポケリニューアルを支えるアーキテクト & PdM 現在、僕はカイポケリニューアルプロジェクトのアーキテクト兼PdMを務めています。 アーキテクトとしての役割 カイポケリニューアルでは、システムとチームを細かく分けていますが、アーキテクトとしては組織の形にとらわれず、さまざまなチームと連携しながらシステム設計や開発プロセスを改善する活動を行っています。 tech.bm-sms.co.jp また、技術面だけでなく組織的な課題の改善にも取り組んでおり、技術とビジネスの橋渡し役としての視点を持ちながら仕事を進めています。 PdMとしての役割 プロダクト組織に閉じずに、全社の業務改善を推進するような責務を負っているBPRチームと一緒に、契約管理システムとカイポケの機能を連動させる仕組みを考えたり、今後必要になってくる認証・認可の仕組みをどう設計するかについても企画を立て、よりセキュアかつスムーズなユーザー体験を提供できるように取り組んでいます。 データプラットフォームの視点も継続 さらに、データプラットフォームチームのメンバーとしても引き続き活動しており、カイポケリニューアルによるデータ移行の仕組みを構築。リニューアル後もスムーズにユーザーが移行できるよう、裏側の仕組みを整えています。 まとめ──未来へ向けて 短期的な目標としては、カイポケリニューアルを無事リリースし、安定性・信頼性を担保しながら、ユーザーの声を反映した改善サイクルを確立することです。 しかし、僕が目指しているのは単なる「リニューアル」ではなく、その先にある新しい価値の創出です。 エス・エム・エスにジョインし、技術と組織の両面からのアプローチが、より良いプロダクトづくりにつながることを実感しています。 今後も、データとプロダクトを掛け合わせながら、新しい価値を創出していくことを目指し、引き続き挑戦を続けていきます。 もし興味を持っていただけたら、ぜひカイポケリニューアルに関する取り組みをチェックしてみてください!
アバター