TECH PLAY

セーフィー株式会社

セーフィー株式会社 の技術ブログ

221

この記事は Safie Engineers' Blog! Advent Calendar 15日目の記事です はじめに こんにちは、あるいはこんばんわ。 第1開発部QCDグループ 小山と申します。 ついに24年も年末となり、今年も懲りず締め切り間際になってから筆を走らせている次第です。 今年のアドベントカレンダーですが、QCDグループの人数も計14名と増えできることも少しずつ増えましたので、改めて 24年版『QCDグループって何をしているグループ?』 をテーマに現状のQCDグループについて紹介をしたいと思います。 過去記事リンクはこちら engineers.safie.link 今回はスクショとかも少なく文字がいっぱいなので安眠効果抜群です。 はじめに 主な業務内容 実施しているテストの種類 テスト自動化に関して <リグレッションテストの自動化率> <リグレッションテスト自動化によって実現できた削減工数> <各プロダクトにおける自動テスト実行頻度> セーフィーのQAエンジニア=テスト/SETエンジニアのこと? <どんなバラツキがあるのか(一例)> その他 最近始めてみたこと セーフィーのQAエンジニアとは(まとめ) 来年度に向けた準備(MVVを決めました) <MVV> 主な業務内容 QCDグループですが通称QAチームといわれることも多いです。 大まかにテストに関わる部分を ”中心に” 担当しているグループということは変わりないです。 担当しているプロダクトとしては以下の図のようなものとなっています 上記一覧の中で、業務システム以外は概ねQCDとしてプロダクトの品質を向上すべく開発業務に携わっています。 基本的に、1メンバーに対し定期リリースのあるIoTデバイス系プロダクト・または新規プロダクトの複数を担当として受け持ってもらっているのが現状です。 プロダクト内でどういった業務(テストなど)をセーフィーのQAエンジニアが行っているかといいますと、プロダクトごとに差分はありますが概ね以下の内容となっています。 実施しているテストの種類 エンハンス内容に対する機能テスト 既存機能に対するリグレッションテスト(エンハンス時に設計したテストの簡易版) 上記をブラックボックステストとして実施しています。 非機能テストについては、プロダクトの要求・要件定義時にPdM側に協力は依頼しつつ、明記してもらえた場合は要求を満たせているかを各担当者ごとに保証するような形で行っていますが、体系的に非機能についても保証ができているとは言いづらいのが現状ではあります。 テスト自動化に関して 思い返せば3年前になりますね。 テスト自動化について動き始めた当初は、リグレッションテストの工数削減を目的としてテスト自動化を進めてきました(毎月楽になる未来を想像していた) しかしながらふたを開けてみると、月に一度実行しないとメンテナンスを短期間で終わらせないといけないこともあり、上手く削減できているという実感を得ることは難しかったです。 そこでリグレッションテストの実施工数削減だけでなく 毎日の成果物としてコミットされるエンハンスに対し自動テストを動かすことで、不具合を早期に発見しプロダクトの品質を向上させる 手動でしかできない所を注力してテストを実行できる環境を作る 上記を目的に加え自動テストのシナリオを大きく見直しました。 現在の実績として、リグレッションテストの自動テスト化の主要なプロダクトについては以下の進捗となっています。 <リグレッションテストの自動化率> <リグレッションテスト自動化によって実現できた削減工数> <各プロダクトにおける自動テスト実行頻度> 来期以降に関してはリグレッションテストだけではなく、影響範囲として漏れがちな直近でエンハンスがないプロダクトやソリューションも含め実装対象としていけるよう準備を始めています。 実行頻度についても現状より多くのプロダクトで毎日実行できることを目標に設定し、トラブルが発生してしまった場合に備え自動テストの実行結果をきっかけにして素早く異常に気付ける体制を築いていけるようにしていきたいと考えています。 自動テスト対象を増やし実行頻度をあげることで、リグレッションテストにかかる工数やエンハンスが暫くなかったプロダクトやサービスにかかる保守工数を下げ、改善活動や新規プロダクトに対するテストに注力できる体制を実現できるようになる(はず) セーフィーのQAエンジニア=テスト/SETエンジニアのこと? と、ここまで書いてきてセーフィーのQAエンジニアは テストエンジニア/テストマネージャー or SET(Software Engineer in Test)エンジニア のことなのかな?と思われてしまいそうですが・・・ いわゆる「良いプロダクト」を出すために様々なことを行うQAエンジニアとして、テスト活動だけでなく要件定義~リリース後のフェーズでプロダクト全体の品質を高められるように(担当者によってバラツキがあるのが現状ですが)活動を行っております。 <どんなバラツキがあるのか(一例)> ビジネスとして成り立つか(利益を生むことができるか) サポート部門の運用を踏まえ、特殊対応をしなくてよいか PoC(概念検証)実施時、何に気を付けなければならないか、目的がブレていないか 上記については体系的な知識の習得方法があるわけではないため、個人の経歴・経験・センスによって品質保証活動での粒度がバラついてしまっています。 このバラツキに関しては来期以降も解消に向け継続して取り組みたいと考えています。 対応案の一つとして、最近QAエンジニアとしてセーフィーに加わってくださったメンバーの方が、各フェーズで行ったほうがいい/注意しなければならない指針と観点を作成してくれていますので、近いうちに発信してくださるはず・・・! その他 最近始めてみたこと 最近ですが社内ツールのエンハンスを開発しているプロダクトチームに対して「品質とは?」というテーマで勉強会を行った方がいます。 こういった啓蒙活動はプロダクトだけでなく、開発本部全体ゆくゆくは営業本部なども含め全社に対して行っていけるようにグループとして準備していきたいと考えています。 ※参考:狩野モデルとは?5つの「品質」や、導入するメリット・注意点を解説 https://service.shiftinc.jp/column/10933/ セーフィーのQAエンジニアとは(まとめ) 現状のセーフィーのQAエンジニアは、基本的なテストエンジニア/テストマネージャーとしての経験を活かし、 『テスト活動やE2Eテストの自動化やプロセスの改善などの品質を向上させるための様々な活動 を各自の希望に沿って行うエンジニア』 です。 今後はテスト活動以外で様々な品質を向上させるために”改善活動”を行い、より良い・価値のあるプロダクトをお客様に迅速に提供できるように来期からは準備を進めていきたいと考えています。 来年度に向けた準備(MVVを決めました) 急に話の内容が変わりますが、月日は早いもので私が入社してから3年が経過しおかげさまでQCDグループの活動領域も人員も増えてきました。 (業務委託メンバー合わせ14名、25年からは計16名) 様々な考えや経歴を持つ方がいて、個性豊かでいいグループになってきたのではないかと個人的には思っております。 そんな中、グループとして1つの共通認識があると業務を進めやすいという話がメンバーから上がりましたので、組織開発を担当するエンジニアリングオフィスとも相談しつつQCDグループのMVV(Misson Vision Values)を策定することができました。 ※策定までの過程・苦労は25年内にQCDのグループリーダーが書いてくれるはずです。 <MVV> Misson : 高品質・適正価格の「映像ソリューション」を提供し、あらゆる産業の現場DXを実現する。 Vision: 創る組織で開発における品質課題に目を向け、品質文化に根ざした改善活動をおこなえるようにする。 Values : より良い品質にしていくために品質とは何かを定義して開発本部全体に広げる。 広げるためにも開発プロセス改善をする(もしくはしてくれという提案をする) 品質改善をし続けるために新しい技術やプロセスを取り入れ1人1人が成長する 2025年からはMVVに沿ってセーフィーという会社の品質を向上させるため真摯に品質改善を続け、グループ一丸となってテストだけではなく改善活動に取り組みたい ・・・と目標を宣言させていただきます。 どういった活動をしてどういう効果があった/効果が出にくかったのかは、来年の年末に施策と共に振り返ることができればなと思っております。 来年も価値のあるプロダクトをお客様に届けられるようにテスト及びそれ以外の領域で活動できればと思います。
アバター
この記事は Safie Engineers' Blog! Advent Calendar 14日目の記事です はじめに はじめまして、サーバーサイドエンジニアの大町です。2024年も早くも年末になりました。年末ということで今年の技術トレンドを振り返りたくなってきたので、Qiitaのブログ記事1万本のデータを分析してみました。 この記事では、2024年はどのような技術が熱かったかを分析した結果とその分析方法について共有したいと思います。 はじめに Qiita APIを使ったデータ収集と分析 データ収集の方法 データ分析の方法 おまけ(バイグラム) さいごに Qiita APIを使ったデータ収集と分析 今回はQiitaの記事を分析したのですが、Qiitaというサービスを選んだ理由はその知名度とデータ収集の容易さです。 まず知名度ですが、Qiitaは技術に関する情報を共有するサービスとして有名な方だと思います。その会員は120万を超えるらしいです。日本のITエンジニアが144万人ということを考えると、多くのエンジニアがなんらかの形でQiitaというサービスを使っていることになります。 corp.qiita.com また、データ収集の容易さですが、Qiitaは外部の開発者向けに API を公開しています。それを使うことで整形された形でのデータを簡単に収集することができます。Qiitaは基本的に技術記事が投稿されますので、技術以外の記事のデータが混ざるということはなく、世の中のエンジニアがどういう技術を使っているのかを知るには適したサービスです。 データ収集の方法 Qiita API は 記事の収集や投稿など多くのAPIが用意されています。今回データを収集するのに使ったAPIは記事の一覧を取得するAPI GET v2/api/items です。このAPI を用いると、最新の記事から順番に記事の内容を取得することができます。APIのレスポンスには、タイトル・内容・タグ・いいねの数などのデータが含まれます。 パラメータとしてpage(ページ番号)とper_page(ページあたりの記事数)を指定することが可能です。 例えば、以下のようなURLをブラウザに打ち込むと最新の記事のデータ20件を取得できます。(制限はありますが、特に認証しなくてもデータを得られます) https://qiita.com/api/v2/items?page=1&per_page=20 ページあたりの記事数(per_page)を100にして、page=1 からpage=100 までのデータを取ることで1万本の記事を取得しました。2024/12/1に記事を取得したので最新のものは12/1です。最も古いものは2024/10/28でした。ということで、約1ヶ月分の記事1万本を収集することができました。 データ分析の方法 タグを使った分析 Qiitaは記事作成の際に、記事に対してタグを付与することができます。そのタグの使用頻度を求めることで今よく使われている技術がわかりそうです。 結果は以下のようになりました。 <タグの頻度TOP10> 順位 タグ 頻度 1 Python 1033 2 初心者 826 3 AWS 652 4 JavaScript 423 5 AI 297 6 React 271 7 Ruby 264 8 TypeScript 256 9 Docker 226 10 Rails 206 1位はPythonということで、他を圧倒していますね。5位に「AI」がランクインしていることからAI系の文脈でよく書かれていそうですね。 2位が「初心者」でした。これは技術トレンドを調べるという意図からは外れたデータですが、Qiitaは初心者向けに書かれた記事が多いということがわかります。今回集めたデータはQiitaのみなので、初心者向けの記事が多いといったデータの偏りはありそうです。 1位のPythonが他を圧倒したというのも初心者向けの記事が多いからかもしれませんね。 記事のタイトルを使った分析 次に記事のタイトルを使った分析を行いました。分析方法はタグの場合とほとんど同じで、タイトルの中でよく使われる単語を求めました。ただ、タイトルはタグのように単語単位で分けられているわけではないので、まずタイトルを単語に分割する必要があります。 この処理は「単語の分かち書き」と呼ばれます。さらに「です」や「ます」など今回の分析には不要なワードも除きたいですね。 このような処理には、形態素解析ツールが便利です。形態素解析は自然言語処理(NLP)の一つで、 文を最小の単位(形態素)に分解し、分解した形態素に対して品詞などの情報を付与する作業のことをいいます。形態素解析ツールには様々ありますが、今回は手軽に使えるJanomeというツールを使いました。 Janomeでは数行のコードで形態素解析ができます。 以下のコードで「私は東京で働くエンジニアです。」という文を形態素解析してみました。 from janome.tokenizer import Tokenizer # Janomeの形態素解析器を初期化 tokenizer = Tokenizer() title= "私は東京で働くエンジニアです。" # 文をトークン(形態素)に分割してリストにする tokens = tokenizer.tokenize(title) for token in tokens: print (token) コードを実行すると以下のような出力が得られます。 私 名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ は 助詞,係助詞,*,*,*,*,は,ハ,ワ 東京 名詞,固有名詞,地域,一般,*,*,東京,トウキョウ,トーキョー で 助詞,格助詞,一般,*,*,*,で,デ,デ 働く 動詞,自立,*,*,五段・カ行イ音便,基本形,働く,ハタラク,ハタラク エンジニア 名詞,一般,*,*,*,*,エンジニア,エンジニア,エンジニア です 助動詞,*,*,*,特殊・デス,基本形,です,デス,デス 。 記号,句点,*,*,*,*,。,。,。 「私は東京で働くエンジニアです。」という文が小さな単位に分割されていますね。さらに品詞や読み方の情報なども付与されています。 今回は形態素解析を記事のタイトルに対して行い、その結果から単語の頻度を求めました。 まず、名詞のみを取り出して頻度を調べてみた結果が以下となります。 <名詞の頻度TOP10> 順位 単語 頻度 1 方法 746 2 AWS 408 3 AI 401 4 作成 381 5 Python 378 6 環境 341 7 化 308 8 開発 307 9 データ 276 10 ファイル 264 タグとはちょっと違ったデータが出てきました。一番多いのが「方法」ですね。2位と倍くらい違います。 全体的にみて技術用語より一般的な用語が多く出てきてしまいました。そこで、取り出す用語を固有名詞に絞ってみました。 <固有名詞の頻度TOP10> 順位 単語 頻度 1 AWS 336 2 AI 230 3 Python 205 4 API 136 5 C 124 6 React 108 7 Google 103 8 Rails 100 9 GitHub 99 10 Cloud 97 意図した感じのデータが取れました。AWSが一位です。 Cが5位にランクインしているのは少し驚きです。 7位がGoogleで10位がCloudなので、これはGoole Cloud ~ が多かったのかもしれません。 解析ツールの品詞情報の揺れ ここでAWSの頻度を見ていて気づいたのですが、ちょっとおかしいですね。 上の「名詞」で取り出した時のAWSの頻度は408ですが、「固有名詞」で取り出した場合は336と頻度が小さくなってしまいました。どういうことでしょうか。 同じAWSという単語でも「固有名詞」に分類されることもあれば、別の品詞に分類されるなど解析結果に揺れがあるのかもしれません。 そこで品詞の解析結果の揺れについて調べるために、「AWSについて学んだこと」「AWSを使ったインフラ構築」という2つの文でAWSの品詞に差分があるかJanomeを使って検証してみました。 「AWSについて学んだこと」の場合 AWS 名詞,固有名詞,組織,*,*,*,AWS,*,* <- 固有名詞として分類 について 助詞,格助詞,連語,*,*,*,について,ニツイテ,ニツイテ 学ん 動詞,自立,*,*,五段・バ行,連用タ接続,学ぶ,マナン,マナン で 助詞,接続助詞,*,*,*,*,で,デ,デ こと 名詞,非自立,一般,*,*,*,こと,コト,コト AWSが固有名詞で分類されています。 「AWSを使ったインフラ構築」 AWS 名詞,一般,*,*,*,*,AWS,*,* <- 一般名詞として分類されている を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ 使っ 動詞,自立,*,*,五段・ワ行促音便,連用タ接続,使う,ツカッ,ツカッ た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ インフラ 名詞,一般,*,*,*,*,インフラ,インフラ,インフラ 構築 名詞,サ変接続,*,*,*,*,構築,コウチク,コーチク AWSが一般名詞で分類されていますね。 同じAWSでも異なる分類のされかたをしていました。 一般に形態素解析では辞書のデータをもとに品詞を特定するので、AWSという単語は辞書に載っていなかったのかもしれませんね。 辞書に載っていない単語は未知語と呼ばれ、解析ツールが周囲の単語などから予測して品詞を求めます。その結果は周囲の単語に依存するので結果に揺れが生じることがあります。 結果の揺れに対する解決策は形態素解析ツールに搭載されている辞書にAWSという単語を追加すれば揺れなく分類可能ですが、今回は大雑把に傾向がつかめれば良いのでそこまではしていません。 おまけ(バイグラム) 最後にバイグラムについても出してみました。 *1 バイグラムとは2単語が連続した文字列です。一般にN単語またはN文字が連続した文字列をn-gramと言います。 なぜ出してみたかったかというと、先ほど出した名詞での頻度分析の結果を10位までしか表には出していなかったのですが、実は11位が「構築」という単語でした。 6位が「環境」なので、「環境構築」という言葉が分割されたのだろうと思い、それを確かめてみたくなりました。 <バイグラムの頻度TOP10> 順位 バイグラム 頻度 1 (環境, 構築) 131 2 (初心者, 向け) 80 3 (Next, js) 79 4 (生成, AI) 72 5 (対処, 法) 58 6 (文字, 列) 48 7 (Raspberry, Pi) 39 8 (ilasm, stack) 39 9 (stack, machine) 39 10 (解決, 方法) 38 やっぱり、環境構築でした。環境構築、たしかに大変ですよね。 生成AIはトレンディですね。このブログで調査するためのコードの大部分を生成AIで作成しました。 Raspberry Pi はよく聞くのでハードウェアへの入門として触ってみたいと思っているのですが、まだ触れられてません。来年こそは触ってみたいです。 生成AIやRaspberry Pi などのように、1単語の頻度ではTOPに出てこなかった単語が出てきたのでバイグラムも有用な情報ですね。 さいごに 今回の記事では、Qiita1万本の記事を使って技術のトレンドを調査してみました。普段、仕事ではデータと向き合うことはないので新鮮な気持ちになりました。 結果としては、AWSやPythonといった技術が(Qiitaコミュニティでは)人気だということがわかりました。 分析方法はタグや単語の頻度を求めるという単純な方法でしたが、それでも大雑把な傾向は見られたと思います。もし大量のテキストデータに出会う機会があれば、 単語の出現頻度を眺めてみてはいかがでしょうか。 *1 : 名詞に絞ってから、連続する2単語を出しているので正確にはバイグラムではない
アバター
こんにちは!セーフィー第2開発部のAndroidエンジニアのジェローム( @yujiro45 )です。 この記事はセーフィー株式会社 Advent Calendar 2024 の12月13日の記事です! 2024年2月1日、360°全方位を広範囲に撮影できる魚眼レンズを搭載した新しいカメラ「 Safie GO 360 」が公開されました。このカメラのプレビューをアプリで表示するために、3Dモデルを使用する必要がありました。この記事では、Androidでどのようにこれを実現したかを説明します。٩( ᐛ )و 半天球カメラの動画再生の表示する方法 1. 3Dモデルを表示する 2. テクスチャマッピング 3. 画角 ジェスチャー 最小・最大ズームの距離計算 回転と移動 タップ位置へセンタリング まとめ 半天球カメラの動画再生の表示する方法 Safieビューアーのストリーミング画面はまだCompose化されていないので、この記事ではxmlの実装を紹介しますが、composeでも同じロジックです。 1. 3Dモデルを表示する 👇10月に書いた記事に関する記事と深く関連していますので、まだ読んでいない方はぜひご覧ください〜。 engineers.safie.link 360°全方位を広範囲に撮影した映像を表示するために、半球の3Dモデルが必要です。カスタム3Dモデルはコードで作成することもできますが、あまりにも複雑で時間がかかるため、Blenderで3Dモデルを作成し、それを使用することにしました。 前回の記事で書いたように、SceneViewでは .glb と .glTF ファイルしかサポートされていません。どちらか一方を選択する必要がありますが、 .glb ファイルの方が軽く、効率的であるため、 .glb を使用することにしました。 sceneView.apply { // 3Dモデル作成 val modelNode = ModelNode( modelInstance = modelLoader.createModelInstance( R.raw.hemisphere ) ) // モデルの位置と向きの設定 modelNode.position = Position(x = 0f , y = 0f , z = 0f ) modelNode.rotation = Rotation(x = 90f , z = 180f ) // モデルを追加する addChildNode(modelNode) } 2. テクスチャマッピング カメラの動画再生ではExoPlayer使用しています。 ExoPlayerで再生している映像をもとに、3Dモデルのテクスチャにマッピングするために、 ARでビデオを表示した時 に作成した ExoPlayerVideoMaterial を使います。 sceneView.apply { // 3Dモデル作成 val modelNode = ModelNode( modelInstance = modelLoader.createModelInstance( R.raw.hemisphere ) ) // 動画再生によるExoPlayer作成 val exoPlayer = ExoPlayer... // ExoPlayerのカスタムVideoMaterial作成 val exoPlayerVideoMaterial = ExoPlayerVideoMaterial( engine, exoPlayer, materialLoader ) // モデルの位置と向きの設定 modelNode.position = Position(x = 0f , y = 0f , z = 0f ) modelNode.rotation = Rotation(x = 90f , z = 180f ) // モデルを追加する addChildNode(modelNode) } 上記のコードをそのまま使うと、SceneViewが3Dモデルの背面にテクスチャをマッピングします。そのため、コンテンツが逆方向にマッピングされるような見た目になってしまいます。 理想 現実 これを修正するには、GitHubで説明されているように、モデルのx 軸上のスケールを反転させる必要があります。 github.com modelNode.scale = Scale(x = - 1f , y = 1f , z = 1f ) いい感じですね!🥳 3. 画角 Safie GO 360カメラは、壁と天井の2つのpositionに設置できます。 横向き 下向き 撮影向きによって、3Dモデルを回転させる方法は異なります。壁に設置された場合、動きは頭の動き(上下、左右)に従います。 しかし、天井に設置された場合は、3Dモデルを宙返りしないような制限を入れる必要があります。 SceneViewのデフォルトの挙動を使用すると、3Dモデルをどの方向にも回転させ、任意のスケールでズームイン/ズームアウトができますが、ユーザーが3Dモデルの背面を見ることができないようにし、また無限にズームインやズームアウトできないようにした方がいいです。ソースコードを確認すると、SceneViewの CameraManipulator パラメーターはデフォルトで設定されていることになっています。 open class SceneView @JvmOverloads constructor ( // ... /** * Helper that enables camera interaction similar to sketchfab or Google Maps. * * Needs to be a callable function because it can be reinitialized in case of viewport change * or camera node manual position changed. * * The first onTouch event will make the first manipulator build. So you can change the camera * position before any user gesture. * * Clients notify the camera manipulator of various mouse or touch events, then periodically * call its getLookAt() method so that they can adjust their camera(s). Three modes are * supported: ORBIT, MAP, and FREE_FLIGHT. To construct a manipulator instance, the desired mode * is passed into the create method. */ cameraManipulator: CameraGestureDetector.CameraManipulator? = createDefaultCameraManipulator(sharedCameraNode?.worldPosition), // ... ) : SurfaceView(context, attrs, defStyleAttr, defStyleRes) https://github.com/SceneView/sceneview-android/blob/2969a2c5ef00e5e5a0bccb29053e33fd93fcc47d/sceneview/src/main/java/io/github/sceneview/SceneView.kt#L184-L199 望む結果を達成するには、それを削除する必要があります。しかし、ソースコードを編集できないため、SceneViewを継承した新しいクラスを作成し、 cameraManipulator のパラメーターを null に設定する必要があります。 class CustomSceneView @JvmOverloads constructor ( context: Context, attrs: AttributeSet? = null , defStyleAttr: Int = 0 , defStyleRes: Int = 0 ) : SceneView( context, attrs, defStyleAttr, defStyleRes, cameraManipulator = null // <--- ここ ) ただし、 cameraManipulator を null に設定すると、ユーザーのすべてのジェスチャーが削除されてしまいます。ということは、自分のジェスチャーを開発するしかありません。 ジェスチャー SceneView には、カスタムジェスチャーを実装するために setOnGestureListener() があります。 fun setOnGestureListener( onDown: (e: MotionEvent, node: Node?) -> Unit = { _, _ -> }, onShowPress: (e: MotionEvent, node: Node?) -> Unit = { _, _ -> }, onSingleTapUp: (e: MotionEvent, node: Node?) -> Unit = { _, _ -> }, onScroll: (e1: MotionEvent?, e2: MotionEvent, node: Node?, distance: Float2) -> Unit = { _, _, _, _ -> }, onLongPress: (e: MotionEvent, node: Node?) -> Unit = { _, _ -> }, onFling: (e1: MotionEvent?, e2: MotionEvent, node: Node?, velocity: Float2) -> Unit = { _, _, _, _ -> }, onSingleTapConfirmed: (e: MotionEvent, node: Node?) -> Unit = { _, _ -> }, onDoubleTap: (e: MotionEvent, node: Node?) -> Unit = { _, _ -> }, onDoubleTapEvent: (e: MotionEvent, node: Node?) -> Unit = { _, _ -> }, onContextClick: (e: MotionEvent, node: Node?) -> Unit = { _, _ -> }, onMoveBegin: (detector: MoveGestureDetector, e: MotionEvent, node: Node?) -> Unit = { _, _, _ -> }, onMove: (detector: MoveGestureDetector, e: MotionEvent, node: Node?) -> Unit = { _, _, _ -> }, onMoveEnd: (detector: MoveGestureDetector, e: MotionEvent, node: Node?) -> Unit = { _, _, _ -> }, onRotateBegin: (detector: RotateGestureDetector, e: MotionEvent, node: Node?) -> Unit = { _, _, _ -> }, onRotate: (detector: RotateGestureDetector, e: MotionEvent, node: Node?) -> Unit = { _, _, _ -> }, onRotateEnd: (detector: RotateGestureDetector, e: MotionEvent, node: Node?) -> Unit = { _, _, _ -> }, onScaleBegin: (detector: ScaleGestureDetector, e: MotionEvent, node: Node?) -> Unit = { _, _, _ -> }, onScale: (detector: ScaleGestureDetector, e: MotionEvent, node: Node?) -> Unit = { _, _, _ -> }, onScaleEnd: (detector: ScaleGestureDetector, e: MotionEvent, node: Node?) -> Unit = { _, _, _ -> } ) https://github.com/SceneView/sceneview-android/blob/2969a2c5ef00e5e5a0bccb29053e33fd93fcc47d/sceneview/src/main/java/io/github/sceneview/SceneView.kt#L819-L839 イベントがたくさんありますが、半天球カメラの場合は以下の実装しか必要がありませんでした。 onMove → ドラッグ操作の時カメラを回転するために onScale → 最小・最大ズームのために onSingleTapConfirmed → プレイヤーのコントロールボタンを表示・非表示するために onDoubleTap → ダブルタップ位置へセンタリングするために 最小・最大ズームの距離計算 ズームイン/アウトの動きは基本的にカメラが軸に沿って移動することで実現されます。最大ズームの時には、カメラの位置を(0, 0)に設定し、最小ズーム(最大ズームアウト)の場合はカメラの移動範囲をモデルの外側が映らないように制限したいです。 最大ズームは大きな問題ではありませんでした。なぜなら、カメラの位置(x, y)が 0 より下に行かないように制限すれば上手くいきました。しかし、最小ズームの場合は、カメラが到達できる最遠のポイントを決める必要があります。これは球体の半径とカメラの FOV の設定を元に算出できます。 tan(FOV / 2) = r / d → d = r / tan(FOV / 2) 動画再生領域が縦長の場合に、最小ズーム状態で左右が見切れてしまいました。そのため、画面のアスペクト比を考慮する必要がありました。 // 球の半径を設定する private val aspectRatio: Float get () { val cameraViewAspectRatio = width.toFloat() / height.toFloat() return if (cameraViewAspectRatio >= 1f ) { // 横長の画面の場合は単位球の半径 1 をそのまま利用する 1f // 球体は半径を1にしておくと計算が楽 } else { // 縦長の画面の場合は、 FOV が vertical な設定の関係から、半径相当のサイズをアスペクト比を利用して変換する 1f / cameraViewAspectRatio } } // z 軸上のカメラと半球面モデルの最大距離 private val maxDistance: Float get () = aspectRatio / tan(Math.toRadians(FOV / 2f )).toFloat() 結果を見てみましょう! 横長 縦長 ズームできました〜🥳 回転と移動 Androidでは、 GestureDetector を使うと、ユーザーが画面にタッチした位置の(x, y)座標を取得できます。デフォルトでは、原点 (0, 0) はビューの左上隅にあります。 ユーザーがドラッグしている方向を特定するには、2つのポイント間のVectorを計算する必要があります: AB(x2-x1, y2-y1) の公式を使うと、ユーザーがスワイプした方向を特定することができます。 fun drag(from: Pair < Float , Float >, to: Pair < Float , Float >) { val previousPointX = from.first val previousPointY = from.second val currentPointX = to.first val currentPointY = to.second val dx = currentPointX - previousPointX val dy = currentPointY - previousPointY when (cameraControlMode) { CameraControlMode.CEILING -> { // カメラを回転する } CameraControlMode.WALL -> { // カメラを回転する } } } また、カメラの回転角度が制限内に収まるように調整しないといけないです。 球体の半径(r)と現在の距離(d)を元に最大回転角(α)を算出できます。 α = atan2(r, d) しかし、カメラの回転は画面中心を基準に行われるため、 FOV に応じた調整が必要です。 α = atan2(r, d) - (FOV / 2) /** * カメラの回転角度が制限内に収まるように調整を行う * * @param x x軸中心での回転角度 (deg) * @param y y軸中心での回転角度 (deg) * @return Pair<調整後の x 軸中心での回転角度 (deg), 調整後の y 軸中心での回転角度 (deg)> */ private fun adjustCameraNodeRotation(x: Float , y: Float ): Pair < Float , Float > { // 距離と球体の半径を元に最大回転角を算出 val rotationLimit = atan2( 1f , actualDistance) val rotationLimitDegree = Math.toDegrees(rotationLimit.toDouble()) // 球体外の写像を避けるために、 FOV を元に回転角をさらに制限 val xRotationLimit = if (rotationLimitDegree > (FOV / 2f )) { (rotationLimitDegree - (FOV / 2f )).toFloat() } else { 0f } when (cameraControlMode) { CameraControlMode.CEILING -> { // x 軸の縦回転は -90 deg から 0 deg の範囲となる val xAxisRotation = x.coerceIn(X_AXIS_ROTATION_LIMIT, X_AXIS_ROTATION_LIMIT + xRotationLimit) return Pair (xAxisRotation, y) } CameraControlMode.WALL -> { // FOV は縦方向を基準としているため、 y 軸方向の横回転はアスペクト比を元に変換した FOV 値を算出する val aspectRatio = width.toFloat() / height.toFloat() val hFOVHalf = Math.toDegrees(atan2(aspectRatio * tan(Math.toRadians(FOV / 2f )), 1.0 )).toFloat() val yRotationLimit = if (rotationLimitDegree > hFOVHalf) { (rotationLimitDegree - hFOVHalf).toFloat() } else { 0f } val xAxisRotation = x.coerceIn( - xRotationLimit..xRotationLimit) val yAxisRotation = y.coerceIn( - yRotationLimit..yRotationLimit) return Pair (xAxisRotation, yAxisRotation) } } } 横向き 下向き これもいい感じですね!🥳 タップ位置へセンタリング Safie Viewerでは、3Dモデルをダブルタップするとダブルタップした位置へセンタリングするという機能があります。3Dモデルの外側だと、普通に真ん中に最大ズームします。 それを実現するために、SceneViewの CollisionSystem を使用することで、ユーザーが3Dモデルをタップした位置を検知します。 setOnGestureListener( onDoubleTap = { motionEvent, _ -> val hitTest = collisionSystem.hitTest(motionEvent).firstOrNull { it.node == modelNode } if (hitTest != null ) { // 3DモデルのhitTest.pointの(x, y)をTapした! } else { // 3Dモデル外部をタップした } }, ) 横向き 下向き ただ、SceneViewのCollision Systemは四角いボックスとして機能されています。そのため、3Dモデルが四角形でない場合でも外側をクリックしてもタップイベントはモデルに当たることになります。 github.com 3Dモデルは半球形なので、外側にいる場合でも3Dモデルでタッチイベントがトリガーされてしまいました。 この問題を修正するために、3Dモデルの前に平面を配置しました。そして、ユーザーのタッチイベントのx座標とy座標に基づいて、それが3Dモデルの内側か外側かを知ることができます。 タップイベントは点が円内にあるかを確認するには、円の中心が位置 (0, 0) にあると仮定して、次の式を適用する必要があります: x² + y² ≤ d /** * 3Dモデルの外側をタップしているかどうか * @param x タップしたx座標 * @param y タップしたy座標 */ private fun isOutside3dModel(x: Float , y: Float ): Boolean { // 3Dモデルの外側をタップしている場合、nullにならない val outsideModelTouchPlaneHitTest = collisionSystem.hitTest(x, y) .firstOrNull { it.node == outsideModelTouchPlaneNode } ?: return false // ヒットテストの座標 (x, y) が半径 1 以内にある場合、3Dモデルのタップしている val isTouchInside = outsideModelTouchPlaneHitTest.point?.let { it.x.pow( 2 ) + it.y.pow( 2 ) <= 1 } ?: false return ! isTouchInside } Before After まとめ 半天球カメラの動画再生を表示する機能を開発するのは大きなチャレンジですが、たくさん勉強になりました。カスタムジェスチャーの開発は簡単ではなく、三角関数の知識が多く必要でした。しかし、SceneViewを使用すると、衝突システムなどの多くの便利な機能が提供され、希望するものを開発するのが楽になります。今回実装してみた結果もとても良く、スムーズです! この記事を最後まで読んでいただきありがとうございます。 また、この機能の開発に多大な協力をしてくれた同僚に本当に感謝しています。 このような面白い機能を一緒に開発したい方は、ぜひ以下のリンクをご確認ください! open.talentio.com open.talentio.com
アバター
この記事は Safie Engineers' Blog! Advent Calendar 12日目の記事です こんにちは、セーフィー株式会社でフロントエンドエンジニアをしている佐川です。 3Dプリンターでなんらかの入力デバイスや小物をつくることが趣味で、同好の士が増えることを願いながら部内のLTや深堀り会などで作ったものの話などをしています。 今回はその中で話していたことのひとつ、キーボードを作る話を書きたいと思います。実業務とは関係がなく、本当に趣味の話です。 3Dプリンターとはんだごてがあると、作れるものの幅が広がって楽しい パラメトリックモデリングによる3Dモデリングの容易さ あたりについて書いていきます。各工程について詳しくは記載していないため、もし気になったら調べてみてください。 キーボードを自作したい! キーボードを自作する 作りたいキーボードを考える パラメトリックモデリングによるケースのモデリング ファームウェアを書く 組み立てる&手配線 かかった金額 最後に キーボードを自作したい! ここ数年でキーボードを自作する行為はだいぶメジャーになってきた印象があります。 2025年3月に行われる キーボードマーケットトーキョー という自作キーボードをメインに扱う即売会では、協賛企業も含めると70を超えるブースが出展するのだとか…。世は大自作入力デバイス時代ですね。 自作キーボードは市販品とは異なり、採算度外視の自由さが魅力です。 游舎工房のWEBショップ を少し覗くだけで、あまりのバリエーションと各制作者の発想力にただただ震えます。最近だと、キーボードにトラックボールがくっついているのを見たときの衝撃たるや…。 さて、自作キーボードと言っても自作の方法には2種類あります。 売られているキットを買ってきて組み立てる 0から作る プリント基板を発注する 手配線 大体の自作キットは基板、外装(+ファームウェアを焼いたマイコン)がセットになっており、あとは必要な電子部品と好きなキースイッチ・キーキャップを用意すれば、プラモデルをぱちぱち組み立てていく感じでキーボードを作ることができます。 ただ、こんな自由度高く様々存在している自作キットといえど、100%自分が求めている要件を満たすものがあるとは限りません。当時、自分が求めている自作キットは存在していませんでした。ロープロファイルのキースイッチが使えて、格子配列の40%キーボードが欲しいだけなのに…。 妥協したものを買うのもなあ…と思ってキーボードの自作方法を見ていると、基本は電子回路を設計して外部にプリント基板を発注する方法がメジャーなようでした。 プリント基板は海外の制作会社に発注するとおよそ2000円~で作ってもらうことができますが、発注してから届くまでにある程度時間がかかります。(別料金を払えば翌日には出荷してもらえます) まずは作って、気に入らないところがあったら修正して…のサイクルを回したい自分としては、時間とお金が気になります。 また、発注時の最低ロット数は大体5枚なので、個人用に作りたいだけなのに4枚も余らせてしまうのはなんだか微妙という気持ちもありました。 もう少し調べてみると、3Dプリンターで印刷した外装にキースイッチをはめ込み、それらを手で配線していく方法で作っているものを見つけました。 なるほど、それなら100%自分好みに作れますし、ちょっと気に入らないところが出たらすぐに直して印刷してしまえばよいです。無限の可能性を感じます。 ScottoLong Handwired Keyboard 余談ですが、こちらは手配線にこだわるとここまで美しくできるのかと非常に感銘を受けたものです。 キーボードを自作する キーボードを作るにあたってやるべきことは、大まかにこれくらいでしょうか。 作りたいキーボードを考える ケースをモデリングする (回路図を書く) ProMicroやラズパイのようなマイコンボードを使う場合は単純なのであまり書きません マイコンボードに頼らないときは、マイコン、USBコネクタ、リセット・BOOTスイッチ、水晶発振器…などなど、登場人物が多いので書きます ファームウェアを書く フルスクラッチ QMK というキーボードファームウェアのベース 組み立てる&手配線 作りたいキーボードを考える 上のほうでも書きましたが、こんなキーボードが欲しいなと考えました。 キー数40% ロープロファイルスイッチ 格子配列 できるだけ本体を薄くしたい キーボードを作る前は、 hsgw氏のPlaid を使っていました。必要な電子部品たちが装飾も兼ねてきれいに配置されており、とても気に入っているキーボードです。こちらを使い始めてからは完全に格子配列に馴染んでしまい、他の配列に戻れなくなってしまいました…。 パラメトリックモデリングによるケースのモデリング 作りたいキーボード案をもとに簡単にラフを書いたあと、早速3DCADソフトを用いてモデリングしていきます。 ところで、自分は3DCAD、3DCGソフトを扱うのが不得意です。GUI上には膨大な数のアイコンやメニューが列挙されており、自分のやりたいことをスムーズに行うには、ソフトごとでの習熟が求められます。 自分の頭の中では「この平面に穴を等間隔で開けたい」「15mmの壁を足したい」など明確なのですが、それを行うための操作手順が煩雑で、作業に対するストレスがグングン溜まっていきます。 そんなとき、 OpenSCAD というコードベースでモデリングできるソフトウェアを見つけました。 実業務でも趣味でもコードを書いているため、こちらのアプローチにすんなり馴染むことができました。 たとえば「四隅に穴の空いたプレート」を作りたいと思ったら、以下のように書くことができます。 width = 10; length = 20; height = 1; difference() { cube([width, length, height], center=true); for (xpos = [-1, 1], ypos = [-1, 1]) { translate([xpos * (width / 2 - 1), ypos * (length / 2 - 1), 0]) cylinder(h=height, r=.5, center=true); } } 書きっぱなしで読みづらい状態ですが、参考までにキーボードをモデリングした際のコードを以下に置いておきます。 github.com ファームウェアを書く オープンソースで公開されているものがいくつかあり、そちらを用いることで簡単に自作キーボードのファームウェアを作成することができます。 有名なものは以下の2つかなと思います。詳しくはドキュメントなどをご参照ください。 QMK 一番有名なファームウェア Vial QMKベースで、WEBブラウザ上でのキーマップ変更機能を有していて便利 余談ですが、組み込み系の知識が乏しかったので、以下の動画を面白く見てました。 自作キーボードって組込みRustの入門にちょうどいいらしい #ch789 組み立てる&手配線 一気に端折ってしまいますが、モデリングしたケースをSTLファイルに変換して3Dプリンターで印刷するとこんな感じになります。(ネジ止め用のインサートナットを圧入済み…) ケースにキースイッチをパチパチはめて、キースイッチとダイオードを銅線で配線し… マイコンボード(今回は家に転がっていたRaspberry Pi Pico)とキースイッチを配線。 キーキャップはめて完成! (キーキャップの文字やアイコンは、テプラのマット透明テープに印字して貼っています。お手軽) かかった金額 部品名 金額(およそ) ダイオード38個 100円 Kailhロープロファイルスイッチ 38個 2600円 Raspberry Pi Pico 800円 キーキャップ 37個 1200円 3Dプリンタのフィラメントや、はんだとか、こまごま 500円 合計 4000円 …かかった時間を考えるとすごく安い!というわけでもないですが、キースイッチやマイコンなどのパーツは使い回せるので、作り直すときはより安価に作ることができますね。 最後に 後半はかなりふっ飛ばしてしまいましたが、3Dプリンターと手配線でキーボードを自作する話でした。 今後ですが、キースイッチを使いまわしたいときにキースイッチの足に直接はんだ付けしている場合、一度はんだを取り除く作業が必要になり非常に面倒くさいです。 なので付け外しが容易になるソケット(Kailh製やベリリウム銅のものなど)を用いてキースイッチのつけ外しが楽なように作りたいなあ…と考えています。 あとはロータリーエンコーダーをつけたり、一体型だけれど左右分離型のような配置のキーボードとか作りたいですね…。 最後までお読みいただきありがとうございました。年末年始のおともにキーボード作り、いかがでしょうか。
アバター
この記事は Safie Engineers' Blog! Advent Calendar 11日目の記事です はじめに みなさんこんにちは。法務部知財グループの永島です。 セーフィーでは様々な社内研修を行っていますが、今回は知財研修にスポットをあててお話したいと思います。 はじめに 知財研修ってなに? セーフィーの知財研修 入社時の知財研修 希望者は誰でも受講できる任意知財研修 知財研修への想い 知財研修を始めたきっかけは? 入社時の必須研修に知財研修(基礎編)を入れた理由は? 知財研修の対象者を開発や企画だけでなく全社員とした理由は? 知財レビュー(半年に1回)を始めたきっかけは? 経営層への知財レビューを対面で実施している理由は? 最後に、知財研修への想いを教えてください。 おわりに 知財研修ってなに? 知財研修はその名の通り、知的財産に関する研修となります。 一般的な知財研修では一例として以下のようなことを目的として行われることが多いです。 知的財産の理解促進 知的財産(特許、意匠、商標、著作権など)の基礎知識を学び、企業にとっての重要性を理解する。 法的リスクの回避 知財侵害を未然に防ぎ、他社の権利を侵害しないようにする。 知的財産の実務概要理解 出願、中間対応、調査、契約などの知財実務の概要を理解する。 うわー、なんだか難しそう、聞いているうちに眠くなっちゃいそう・・・って内容ですよね。 セーフィーの知財研修 セーフィーの知財研修は「知財をみんなで楽しもう!」をモットーにしています。 楽しみながらも、一般的な知財研修では得られにくい「実情に沿った考え方」と「ネタに気付くカン」を磨くことに重点を置いています。 知財研修を楽しんでもらうための私たちの3つのこだわりを紹介させてください。 その1:わかりやすい資料作り より楽しく受けてもらえるよう、イラストや図表を多用した工夫を凝らした資料作りに取り組んでいます! その2:極力専門用語は使わない 研修を気軽に受けてもらえるよう、専門用語の使用を極力控え、必要な場合はわかりやすい例えを交えて解説するよう心がけています! その3:受講者参加型 研修は基本的にWebで実施しており、研修途中にGoogle Meetの機能を活用したアンケートや、ワーク、ティーブレイクを取り入れることで、受講者がただ聞くだけで終わらない工夫をしています! ティーブレイクの雑談についてどのテーマの話が聞きたいかアンケートを取っている様子⇒⑨ラテアートはじめましたが一番人気でした(笑) セーフィーの研修の種類はいくつかあるのですが、そのうち、知財研修は「入社時の研修」と「希望者は誰でも受講できる研修」の2つがあります。 次はそれぞれの知財研修の内容についてお話します。 入社時の知財研修 セーフィーでは入社時の研修がとても充実しています!詳しくはこちらの記事でご紹介しています。 note.com 知財研修も入社時必須の研修となっているのですが、どんな内容かチラ見せ。 入社時の知財研修では主に以下のような内容を学びます。 知的財産権を取得する目的 特許、意匠、商標の基礎的な知識 セーフィーで取得した特許権、意匠権、商標権の紹介 入社時の研修では、一般的な知財研修に近い内容を扱いつつ、「知財は事業を守り発展させるために、開発や企画部門だけでなく全員が関わるべき重要なテーマである」というメッセージをしっかりと伝えています。 希望者は誰でも受講できる任意知財研修 任意知財研修は上期2回、下期2回の1年間計4回行います。今まで10回の任意知財研修が開催されています。 テーマ1:基礎編 テーマ2:特許編①特許文献の読み方 テーマ3:特許編②発明の捉え方/良い発明の条件 テーマ4:商標編 テーマ5:Safie知財の現状&今後 テーマ6:契約交渉編 テーマ7:2023知財レビュー/Safieの知財方針 テーマ8:著作権編 テーマ9:2024上期知財レビュー テーマ10:特許調査編 この研修は希望者のみの任意参加としていますが、セーフィーでは毎回リアルタイムで約100名の社員が参加しています。アーカイブ配信も行っている中でのこの参加人数は、セーフィーの社員数461名(2024年7月時点)の約4分の1に相当します。セーフィー社員の知的財産に対する関心の高さがうかがえますね! この中で異彩を放っているものといえば「知財レビュー」ですよね。 知財レビューは、上期・下期ごとに出願および登録されたセーフィーの知的財産権の内容を共有する研修です。経営層に関しては別途時間を設けて必須で実施しています。 任意研修のそれぞれの内容については別の回でじっくりお話させてもらえればと思います。 知財研修への想い ここからは、セーフィーで知財研修をやり始めた当事者である、知財グループGLの渡辺さんに、知財研修への想いを質問形式で聞いてみたいと思います。渡辺さんは、2022年1月に知財担当の1人目としてセーフィーに入社して以来、知財部門の立ち上げから知財の責任者として務めています。 知財研修を始めたきっかけは? (渡辺) 私が入社した当初、知財に対して理解のある人がほとんどいなかったからです。 知財活動を本格化していくには、周りの協力を得たり、予算を適切に獲得する必要が出てきます。そうなった時、後々苦労するだろうなというのが目に見えていたため、これは早い段階でテコ入れせねばと思いました。 入社時の必須研修に知財研修(基礎編)を入れた理由は? (渡辺) 基本的な知財リテラシーについては、常に全社員が身に着けている状態にしておきたいからです。 セーフィーは、毎月のように中途社員が入ってきて社員数が増え続けていますので・・・早い段階で確実に聞いてもらえる機会として、入社時の必須研修に目を付けました。 その副産物として、会社として知財を重要視している点はもちろん、知財部門の存在や知財担当の顔についても、初めから知ってもらえるという効果がありました。 知財研修の対象者を開発や企画だけでなく全社員とした理由は? (渡辺) 近年、知財が影響を及ぼす範囲が広がってきているからです。具体的には、従来から重要である「他社にマネされないようにする」だけでなく、近年は「お客様への訴求力を高める」「会社のイメージを上げる」「社員の士気を高める」「経営に新たな視点を与える」等。その様な時代に対応するため、というのが当初の理由でしたが、やっていく中で思わぬ部門に知財のファンが増えたりするのも、楽しみの1つだったりします。 知財レビュー(半年に1回)を始めたきっかけは? (渡辺) もっと知財を身近なものとして、当事者意識を持ってもらいたかったからです。知財レビューでは、実際に出願/登録になった件の事例紹介にも力を入れています。 特にセーフィーのようにSaaS系の技術分野では、当事者も「新しいものを生み出している」という自覚が少ない傾向にあるため、知財を通してそれを見える化し、社員の士気を少しでも上げられたらと思っています。 経営層への知財レビューを対面で実施している理由は? (渡辺) お忙しくてなかなか聞いてもらえないからです(笑)それに、対面ならディスカッションもできて様々な要望を拾うことができ、今後の知財の方針に生かせます。 最近では、全社向けの研修でやったクイズの結果を従業員の意識調査として、経営層にフィードバックすることもあります。この前、知財から距離が遠い筈のCCOや監査役から「実は毎回楽しみにしている」という声を聞いた時は、とても嬉しかったです。 最後に、知財研修への想いを教えてください。 (渡辺) とにかく、まずは知財を楽しんでもらえたらと。いいアイデアって、あれこれ楽しく考える中でたくさん生まれてくるものだと、今までの経験から感じてましたので。 知財に限らず、専門職の世界って素人には中々理解し難いですが、今後も工夫を凝らしていきますので、是非ご期待ください。 おわりに 「知的財産」って聞くと、なんだか専門的で難しそう…と思う人が多いと思います。私たち知財グループは知財研修で少しでもその垣根を取り除くことができればと考えています。 知的財産って、特別なスキルを持った人だけのものじゃなくて、社員全員がちょっとずつ関わることで、もっと強力な武器になります。部署の垣根を越えて学び合えば、きっとお互いに刺激を受けていいアイデアがどんどん生まれるはずです。 私たちはこれからも「知財をみんなで楽しもう!」をモットーにセーフィー独自の知財研修を実施していきます! セーフィーではエンジニアを積極的に採用しています。 興味がある方は是非下記サイトを一度覗いてみてください。 エンジニア職 | セーフィー採用サイト
アバター
この記事は Safie Engineers' Blog! Advent Calendar 10日目の記事です 「社内プチ表彰式」の写真 はじめに みなさんこんにちは。法務部 知財グループの永島です。 セーフィーでは、2022年に知財部門を立ち上げて以来、20件以上の特許が登録されています。 今回は、その中の1件について、上記表彰に応募したところ無事に受賞できましたので、お話いたします。 はじめに 地方発明表彰とは 受賞内容 どんな発明? 本件特許に込めた想い 「社内プチ表彰式」の様子 おわりに 地方発明表彰とは 地方発明表彰は、公益社団法人 発明協会が大正10年から開始した歴史ある表彰で、全国を8地方(北海道・東北・関東・中部・近畿・中国・四国・九州)に分け、各地方から生まれた優れた発明等を表彰するものです。 地方発明表彰の詳細(発明協会Webページ) https://koueki.jiii.or.jp/hyosho/chihatsu/chihatsu.html イメージとしては、「特許の甲子園」みたいな感じです。ただ、その地方大会とはいえ、特にセーフィーが応募する関東ブロックは激戦区で、例年、名だたる大企業が多数応募してきます。そこに、セーフィーのような数年前に上場したばかりのスタートアップが如何に切り込めるか・・・初応募は、まさに挑戦でした。 受賞内容 令和6年度 関東地方発明表彰 「発明奨励賞」   【発明名称】映像解析により人の滞留を検知するシステム  【特許番号】特許第7279241号  【受賞者】谷野 香菜 橋本 貴博 鬼城 渉 藤澤 真之 大友 裕明       柏木 直諒 松田 一輝 沖 総一朗 小嶋 幸恵 単に特許が取れただけでなく、それを第三者機関に評価してもらった結果、大企業と肩を並べて受賞者に名を連ねることができたという事実は、それだけで誇れることであり、会社にとって大きな自信となった筈です。 どんな発明? 特許第7279241号(以下、本件特許)は、 Safie One に搭載された AI-App人数カウント の1つである「立ち入り検知」に関するものです。 その概要については過去に こちらの記事でも紹介済み ですが、もう少し詳しく説明します。 近年、店舗のカメラで撮影した映像を現場のDX に活用する試みがあり、その中で本件特許が生まれました。 ざっくり言うと、上図に示したようなシステムにおいて、人の滞留を見える化するための技術です。 ポイントは、予め検知エリアおいて人の滞留を検知するための条件:①人数②滞留時間を設定しておき、実際にカメラで撮影した映像において①②の条件が満たされた場合に、そのタイミングを出力する(サムネイル表示/タイムライン上にオブジェクト表示)というものです。 利用シーンとしては、例えばレジ待ちが長くなっているシーンを可視化することにより、店員のシフトや接客方法を改善するのに役立ちます。また、例えば売場で特に混雑しているシーンを可視化することにより、売場のレイアウトや商品のラインナップを再考するのにも役立ちます。この様に現場のDXが進めば、店舗側の機会ロスが減り、お客様の満足度向上に繋がります。 さらには、店舗の省人化が図られることにより、日本の大きな課題である働き手不足の解消にも貢献することができます。 本件特許に込めた想い 近年、世の中では監視カメラの用途を現場DXに広げようとする動きが一部見受けられるようになってきたものの、まだ思うようには進んでいません。 その主な要因は、「記録された膨大な映像データの中から、見るべきシーンを特定するのが大変」という点にあり、これが映像データを利活用するうえで大きな壁となっています。 これを克服すべく、AIによる映像解析等に頼る企業もありますが、AIの精度を実用に足るまで上げるのは難しい場合が多く、AIを作るためのコストや時間も馬鹿にならないため、AIの社会実装はなかなか上手くいっていない、というのが現実です。 本件特許は、その様な現実を理解したうえで、多くの発明者が共に現場で議論を重ね、人が考えたロジックをシステムに組み込むことにより、映像データを利活用するための壁を突破しよう、という想いが込められています。 「社内プチ表彰式」の様子 発明協会の表彰式には参加できませんでしたが、その代わりに社内でプチ表彰式を行いました。 当日は、受賞者、森本CTOが参加し、表彰状の授与やスピーチ等で盛り上がりました! 表彰状授与の様子 受賞者の谷野さんのコメント 一言では語り尽くせないくらい困難なプロジェクトでした。当初は「Safie One」が売れるかどうか不安もありましたが、多くの方に選ばれる商品となり、大変嬉しく思っています。 今回の受賞は、チーム全員が一丸となって努力を重ねた結果が実を結んだものです。この成果を手にできたことを心から誇りに思います。 これからも機能改善を重ね、賢くなるカメラである「Safie One」をさらに進化させていきたいです。 森本CTOのコメント これまで、売れない商品に悩まされることも多く、まさに可能性を模索していた時期に「Safie One」は生まれました。これは、チームのやりきる力が生み出した成果です。 今回の受賞は、私たちの努力が評価された結果だと感じており、大きな喜びと誇りを感じています。また、このような表彰への応募は社会的な意義を広げ、セーフィーの認知度を高め、新たな可能性を切り開く大切な取り組みであると確信しています。 今後も、私たちはさらなる高みを目指し、果敢に挑戦し続けます。 おわりに セーフィーでは、上場後に知財活動が本格化しましたが、そこから1年目で種蒔き(出願)⇒2年目で収穫(登録)⇒3年目で外部評価(表彰)と、着実に進化してきました。 これは何といっても、現場で新しい技術がちゃんと生まれていたからです。特にSaaS系の業界においては、大して新しい技術は生まれていないだろう・・・と当事者含め思い込みがちですが、そうではないことが証明できたと思います。 今後もセーフィーは、地道な開発活動を通してイノベーションの現実解を見出し、日本の新たな未来を切り開いていきたいと考えています。 セーフィーではエンジニアを積極的に採用しています。 興味がある方は是非下記サイトを一度覗いてみてください。 https://safie.co.jp/teams/engineering/
アバター
この記事は Safie Engineers' Blog! Advent Calendar 9日目の記事です。 あいさつ こんにちは!セーフィーの井上と申します! 2023年11月に入社し、エンジニアリングオフィスの一員として日々業務に取り組んでいます。 今回はセーフィーの「エンジニアリングオフィス」という部署は一体何をしているのか、皆様への紹介も兼ねて取り組んでいることについてお伝えさせていただきます! あいさつ エンジニアリングオフィスとは? エンジニアリングオフィスのミッション ミッション達成するためには 取り組み内容 テックブランディング向上施策 テックブログ 次のステップへ 開発本部アイデアソン 2024年の進化過程 社内認知の向上と参加者の拡大 第3回での大きな進展 2024年の活動を通して得られた成果 社内認知向上が一定の成果を達成 オンボーディング・ネットワーキング構築の取り組みとして採用 まとめ 終わりに エンジニアリングオフィスとは? エンジニアリングオフィスは、取締役CTO・VPoE、各部室長や各部署と密に連携し、最高のプロダクトをつくるため、エンジニア組織拡大に伴い中長期の組織成長戦略を策定・実行しており、さらなる事業成長を見据え組織の強化を推進しています。 エンジニアリングオフィス発足に至った理由として、弊社のVPoEの谷口が記事を掲載しておりますので、こちらも是非ご覧ください! engineers.safie.link エンジニアリングオフィスのミッション セーフィーはVisionとして「映像から未来をつくる」を掲げています。 このVisionを実現するためには、中長期の戦略を実行できる組織へと常にアップデートし続ける必要があります。 セーフィーが掲げるVisionを実現するべく、エンジニアリングオフィスはプロダクトと人・組織の両輪を支えるために下記ミッションを設定しました。 エンジニア組織の未来を追求し、未来に起きるであろう課題も見通した解決エンジンとなる そのためには「ありたい姿」「こういう組織を作らなきゃいけないよね」というゴールを定め、目標への道筋を明確にすることが重要となります。 ミッション達成するためには ミッションを達成するべく、エンジニアリングオフィスではバックキャスティングの考え方を採用しています。 業務に着手するときは、始めに将来どういう姿になっていたいか・ありたい姿(ゴール)は何なのかを定義します。その後、現状の自分達の立ち位置を確認することで「ありたい姿と現状のギャップ(課題)」を確認します。こうして課題を明確にし、次に何をするべきかの道筋を明確にすることで、ゴールまでの道筋を迷うことなく進むことが出来ます。 取り組み内容 上記を踏まえた上で、実際どのように組織開発に臨んでいるのか?ということを、自分が担当している業務から3つピックアップしてご紹介いたします。 テックブランディング向上施策 まず、自分が担当している業務の1つとして「テックブランディング向上施策」があります。端的に説明しますと、社外のエンジニアからの認知を高める施策を担当しています。 じゃあイベントに参加したりブログを沢山出して社外にアピールしよう!そしたら認知あがるじゃん! ・・・等と、とりあえず目の前のタスクに掛かる前に、まずはバックキャスティングの基本である ・ゴール(あるべき姿・数年後どうなっていたいか) ・課題(あるべき姿と現状のギャップ) ・何をするべきなのか を腰を据えて定義しました。 ゴールを定義した後、そのゴールを達成できるよう道筋を明確にするため中長期計画を立て、ロードマップを策定しました。 ロードマップについて要約すると、以下のようになります。 FY24:社内認知が向上している FY25:社外認知が向上している FY26:セーフィーの組織文化が社内外に浸透している このテックブランディング向上施策の1つにテックブログがありますので、次項ではテックブログを例に具体的に何をしていたかを説明します。 テックブログ 上項で策定したロードマップにおいて、FY24は【社内認知が向上している】ことを目指しています。 テックブログは、世間にセーフィーの活動内容や取り組みを認知頂ける手段として最たるものだと自分は考えています。 しかしながら、そもそも活動内容や取り組みを執筆頂ける方がいないと、テックブログ自体が成り立ちません。 また、「情報を発信する重要性」が浸透していないと執筆して頂ける方も増えていきません。 そのため、上項で策定したロードマップに則り2024年の取り組みとして【社内認知の向上】に努めました。 例えば・・・ 開発本部全体会議にてテックブログの成果報告や成功事例の共有をすることで、テックブログがどの程度見られていてどのような反響があるのかをフィードバック テック系イベントの記事執筆例 Mobile Dev Japan #3 イベントを共同開催した話 - Safie Engineers' Blog! Findy さん主催のイベント「TechBrew in 東京 ~モバイルアプリの技術的負債に向き合う~」にて発表してきました - Safie Engineers' Blog! DroidKaigi 2024に参加してきました! - Safie Engineers' Blog! 勉強会や社内の取り組みをブログで展開して頂けるよう積極的にアピール 取り組み紹介記事の記事執筆例 AWS Startersに参加しました - Safie Engineers' Blog! We held our first English event at Safie, Safie English School! - Safie Engineers' Blog! 開発本部(エンジニア向け)社内アイデアソン始めました - Safie Engineers' Blog! スクラムチームの振り返りに Sailboat Retrospective を導入してみた - Safie Engineers' Blog! 執筆プロセスを改善して、より簡単に書けるプロセスを構築する等の運営プロセスの改善(進行中) 上記以外にも取り組んだ施策はありますが、こういった施策を実施した結果、2023年と比較して自ら執筆される方が増加し、記事執筆のご提案もご快諾頂ける文化が出来上がりました。 また、「この技術の裏側を記事にしたらウケそう」「この知見を是非外部に広めたい」等と記事ネタの提案も頂けるようにもなりました。 今回のアドベントカレンダーについても、「アドカレやります!!」と社内告知した際、皆様が積極的に立候補されたことにより、早い段階で全枠を埋めることが出来ました。 その他にも、他部署の方から「執筆したい」というお声もあがるようになりました。以下の記事は営業本部の松本さんに執筆頂いた記事です。 engineers.safie.link 上記のように、中長期のロードマップ計画に則り、施策を実施し続けた事で社内認知を向上させることができました。 次のステップへ 社内認知を上げるための活動を続け、執筆にご協力頂ける方が増えたことにより記事発信数が増加、テックブログ自体の露出が高まり社外認知も向上しました。 例えば、セーフィーがイベントブースに出展した際、ご訪問頂いた方々から「テックブログ見たことあるよ」等のお声がけを頂く機会が着実に増えています。 このように、ロードマップの各年度の計画が次の計画に繋がるよう設計していくことにより、理想の姿へ一歩一歩進むことができるようになります。 開発本部アイデアソン エンジニアリングオフィスでは、社内ネットワーキングの強化や、エンジニアのナレッジの向上を目的とした取り組みも行っています。 その一環として2024年にスタートしたのが開発本部アイデアソンです。 第1回開発本部アイデアソンの記事はこちら engineers.safie.link ここでも勿論バックキャスティングの考え方で企画・運営を進めています。 この開発本部アイデアソンの目指すべき姿として、以下を定義しました。 セーフィーの企画会議を通過し、正式なプロダクトとして稼働するアイデアを生み出せる場 上述した目指すべき姿を達成するためには、定期的に開催・都度アップデートを行い、業務時間を割いてでも参加する意義のあるイベントにしなくてはなりません。 そのための第一歩としてテックブログ項と同様、こちらもまずは社内認知を高める所からスタートしています。 いくら価値があるとアピールしても、参加者がいなければ開催はできません。 2024年の進化過程 社内認知の向上と参加者の拡大 アイデアソン開始当初はあまり興味を持たれておらず、参加者が少ない状態でのスタートとなりました。 しかし、「楽しかった」「学びが多かった」という好意的な反応や参加者の声が各グループ内で広まりました。 直近のアイデアソンでは、定員上限に近い人数が参加するほどになりました。 第3回での大きな進展 第3回アイデアソンでは、あるアイデアを正式な企画として実現したいという声が上がり、参加者たちによる企画会議に提案するためのチームが立ち上がりました。 この動きは、アイデアソンの目的である「正式なプロダクトとして実現可能なアイデアを生む」に直結しうる成果ともいえます。 2024年の活動を通して得られた成果 社内認知向上が一定の成果を達成 第3回まで開発本部アイデアソンを高頻度で開催したことにより、取り組み内容等の社内認知が向上しました。 「面白そうだから・学びがあるから参加してみたい」という声が他部署からも多く寄せられるようにもなり、社内認知の向上を達成できました オンボーディング・ネットワーキング構築の取り組みとして採用 開発本部アイデアソンは、部・グループを跨いだネットワーキングの向上に効果があると評価を社内で頂きました。結果、新入社員のオンボーディングコンテンツの一環として正式に組み込まれるようになりました。 今後は新入社員と既存社員を混成した人数で計画を組むことを意識し、より円滑なコミュニケーションを早期に構築することを狙っていきます。 上記の通り、2024年では認知向上やアイデアソンに参加することの有用性を証明することができました。 2025年からは、アイデアソンの目指すべき姿に到達できるように、より洗練されたアイデアや提案資料を生むことができるよう更にブラッシュアップを行います。 例えば、企画会議に提案できる資料のアウトプットやプレゼンの内容を充実させるためのレビュー会を実施したり・・・ アイデアがより実現可能で説得力のある形に仕上がるよう様々な施策を実施し、参加者全員に実りのある体験ができる場へとアップデートを行っていく予定です。 まとめ セーフィーはここ数年で事業・組織が大きくなったことで、組織のあるべき姿を中長期を見据えて戦略的に構築するフェーズに入りました。 個人個人の開発生産性を高めて成長を促すだけに留まらず、組織としての成長が重要になってきます。 組織を成長させ続け、新しい技術に挑戦できる組織にアップデートし続けるには、エンジニアリングオフィスが重要視しているバックキャスティングの考え方が活きてきます。 目指すべき姿は何か。現状と理想の姿のギャップ(課題)は何があるのか。実現するためには何をするべきなのか。 ・・・という事を押さえる事で、組織開発を実践できるようになります。 終わりに 本記事では、エンジニアリングオフィスについてご紹介させていただきました。 エンジニアリングオフィスでは、エンジニア組織の組織開発を牽引して中長期の組織戦略立案から実行を推進するメンバーを募集しています! open.talentio.com カジュアル面談から受け付けておりますので、気軽に応募いただければと思います!皆様のご応募、心よりお待ちしております! 最後までお読みいただき、ありがとうございました。
アバター
この記事は Safie Engineers' Blog! Advent Calendar 8日目の記事です はじめに こんにちは、第1開発部でサーバーサイドエンジニアをしている坂上(さかうえ)です。今回は2024年新卒エンジニア研修における成果発表と、その後についてお伝えします。 はじめに 研修の成果発表 サービス運用 運用方針 運用開始後 ナレッジ共有会 最後に 研修の成果発表 我々24新卒エンジニアは、エンジニア研修として「社内課題を解決するプロダクト開発」というテーマについて取り組みました。自身の体験や社員の方々へのユーザーインタビューを経て、異才ランチ(社員同士のランチ代を補助する制度)のマッチングをサポートするisai connectというプロダクトを開発しました。 プロダクトの詳細や、それまでの経緯に関する詳細は、今までの記事をご覧ください。 新卒研修の紹介とチーム開発前にやったこと 2024年新卒エンジニア研修-アジャイル開発編 2024年新卒エンジニア研修-isai connectについて 2024年新卒エンジニア研修-isai connect開発のアウトプット_サーバーサイド 2024年新卒エンジニア研修-フロントエンド開発編 2024年新卒エンジニア研修-インフラ構築編 2024年新卒エンジニア研修-isai connect開発のアウトプット_デバイス編 2024年新卒エンジニア研修-新卒研修の成果発表とその後 ←本記事 研修の成果であるisai connectの成果発表は、2つに分けて行いました。 1つ目は、セーフィー社員全体に向けた発表です。 2024年新卒エンジニアがisai connectを作ったというインパクトを残し、認知してもらうことが主な目的でした。isai connectが解決する課題とターゲットの説明やサービス方針を伝え、より多くのユーザーに使ってもらえるような発表をしました。 2つ目は、開発本部に向けた発表です。 isai connectの開発の中でも以下の3つの内容に絞り、より詳細に説明しました。 ・2024年新卒エンジニアチームとしての開発の進め方 ・isai connectに実装した機能に対する技術的に工夫したポイント ・研修を通して成長した点と今後の意気込み 2つの発表を振り返ると、改めて発表の難しさを実感しました。研修内容が非常に充実していた一方で、限られた時間の中でその内容を効果的に伝えるためには、発表の目的を明確に設定し、それを達成するために内容を厳選する必要がありました。この整理や意思決定には時間を要し、難しさを感じました。 また、発表では、直感的に理解しやすい工夫としてスライドだけでなく、動画も活用しました。その結果、多くの社員に興味を持ってもらい、「興味が湧いた」「使ってみたい」といった前向きな感想をいただくことができました。 こうした声をいただけたことで、今回の発表で設定した目的を達成できたと感じ、とても満足しています。 この経験を通じて、限られた時間で効果的に見せる大切さを改めて学ぶことができました。 以降の章ではサービス運用と研修後の勉強会について説明します。 サービス運用 運用方針 isai connectを実際にセーフィーで使ってもらうために、サービス方針を定めました。 この運用方針で進めるにあたって、配属先であるグループの上長に許可をもらう形で、業務として運用していく形としました。 主な業務内容としては、以下5つです。 isai connect定例ミーティング 隔週30分 議題 サービスの利用状況確認 各自の取り組んだことの進捗確認 相談事項の確認 新規機能開発 ユーザーからの要望や開発メンバーからのアイデアを元に、新規機能についてSlackで開発メンバーと共有し、実装すべきとなった場合にチケットとして発行する バグ修正のチケットの優先順位を加味して、実装していく バグ修正 発生したバグやユーザーからあった要望、そして新たに開発したい機能をチケットとしてまとめ、スクラムマスターが優先順位づけを行ったものを、上から処理していく 主当番 2週間ごとに交代制 お問い合わせ対応 Slackの専用チャンネルを設け、isai connectの利用者からの不具合の報告や要望の一次対応をする 副当番 2週間ごとに交代制 主当番のお問い合わせ対応の補佐 従業員名簿更新作業(※月の最初の週の場合) セーフィーの社員名簿が月初に新しくなるに伴い、更新作業を行う 定期リリース作業(※月の最後の週の場合) 2週間で実装した内容をリリースする 運用開始後 サービス運用を開始すると実際に使用したユーザーから感想を多数いただきました。 isai connectがなければ、関わりがなかったであろう人とランチにいく良い機会になりました 誘いがきた時に、自己紹介が見れるので、事前知識があって嬉しいです さらに、この機能があったらもっと良いなというフィードバックまでいただくことができました。 日程調整の機能までついていたら、さらに手軽になる 誘う時に、誘われる側が異才ランチに行きたい気持ちがあるかどうか、わかるとより誘いやすい 一方、それと同時に以下のような障害対応にも追われました。 isai connectのアカウント作成時に利用規約に同意しようとすると画面が真っ白になってしまう 異才ランチが成立した時に、作成したSlackグループDMの文言が間違っている デバイスの電源を常につけておくと、フリーズしてしまう このように、実装の不備に加え、実際に運用することで初めてわかるような想定以上の不具合に追われ、配属先の業務と並行して対応を行いました。サービス運用を継続しながら引き続き改善を続けています。 また、2024年新卒エンジニアに運用の感想を聞いたところ、ポジティブな意見としては以下のような声がありました。 いろんな方から使ったよと言ってもらえて嬉しい 自分が開発した機能が、他の人に使われている様子が見れて、達成感がある 一方、今後の改善点としては以下のような声がありました。 本業務の合間にまとまった時間を取るのが難しい 開発中には出てこなかった問題が浮き彫りになる 研修時に担当していた分野以外のチケットを取りたかったが、運用となるとハードルが上がってしまう 運用開始から5ヶ月が経とうとしていますが、月に10件弱の異才ランチの実施がisai connectを通じて行われています。 今後は、本来の目的である価値を発揮するために、これまでの運用で得られたフィードバックや障害対応を活かし、更なる機能改善と安定性向上に注力していきます。また、運用を担うチーム体制の見直しを行い、各メンバーが無理なく役割を果たせるよう、業務の分担や支援体制を整えていきます。 ナレッジ共有会 無事にエンジニア研修を終えた後、配属先での実務が本格的に始まりました。研修を通じて築いた2024年新卒エンジニアのつながりを活用するため、私たちからの提案で「ナレッジ共有会」を隔週で開催しております。配属先で学んだ知識や経験を共有して、早く新しい環境に適応し、エンジニアとして成長することが目的です。 この会では、各回で2人の発表者が発表資料を準備し、1人15分ずつ、合計30分間のプレゼンテーションを隔週で行っています。テーマは配属先で得た知見や学びを中心とし、実務で役立つ技術的な内容から、業務効率化の工夫や課題解決のアプローチまで幅広く設定しています。 ナレッジ共有会は、新卒エンジニア同士のつながりを強化するだけでなく、他のメンバーの知識や経験から刺激を受け、新しいアイデアを得る場としても機能しています。今後もこの取り組みを継続し、互いに支え合いながら成長していきます。 最後に 2024年新卒エンジニアのメンバーは、多様なバックグラウンドを持つ仲間が集まりました。その中で、意見が食い違ったり、進め方がなかなか決まらなかったりと、数多くの困難にも直面しました。しかし、チームで協力しながら乗り越え、一つのプロダクトとして形にすることができたことに大きな達成感を感じています。同時に、isai connectをさらに成長させ、多くの方々に価値を届けられるサービスへと進化させていきたいという思いも抱いています。 また、このプロジェクトを通じて築いた仲間とのつながりを大切にし、互いに切磋琢磨しながら成長を続けていきたいと思っています。これからも挑戦を重ね、セーフィーの一員としてさらなる価値を創出していきます。
アバター
この記事は Safie Engineers' Blog! Advent Calendar 7日目の記事です はじめに こんにちは。第4開発部でデバイスエンジニアをしている集路(しゅうじ)です。 今回は2024年新卒エンジニア研修におけるデバイス分野の開発についてお話しします。 はじめに セーフィーでの2024年新卒エンジニア研修と作ったプロダクトの紹介 開発したデバイスの概要 デバイス機能の決定まで 開発上の苦労・工夫点 今後の展望 最後に セーフィーでの2024年新卒エンジニア研修と作ったプロダクトの紹介 セーフィーでは全体研修後、約3ヶ月のエンジニア研修があり、エンジニアとしての基礎を学びつつ、社内課題を解決するプロダクトを開発しました。 課題選定から開発言語、体制まで全て自分たちで決める形式で、私たちは「isai connect」を開発しました。これは、他部署の方とランチに行くと会社がランチ代を負担してくれる「異才ランチ」制度をより活用し、活発化を図るためのプロダクトです。 詳しくは以下の記事でご覧ください。 新卒研修の紹介とチーム開発前にやったこと 2024年新卒エンジニア研修-アジャイル開発編 2024年新卒エンジニア研修-isai connectについて 2024年新卒エンジニア研修-isai connect開発のアウトプット_サーバーサイド 2024年新卒エンジニア研修-フロントエンド開発編 2024年新卒エンジニア研修-インフラ構築編 2024年新卒エンジニア研修-isai connect開発のアウトプット_デバイス編 ←本記事 2024年新卒エンジニア研修-新卒研修の成果発表とその後 セーフィーではカメラを扱っていることもあり、新卒エンジニア研修でも組み込み開発の領域も体験するため、 RaspberryPi とカメラを用いるという条件がありました。 我々の開発したプロダクト「isai connect」では、Webの開発が主であり、どのようにしてデバイスをサービスに結びつけるのか、など苦労した点も多くありました。開発したデバイスの概要や、その紆余曲折についてご紹介します。 開発したデバイスの概要 まず、開発したデバイス「Receipt Sender」の概要・機能について説明します。 このデバイスでは、名前の通りレシートの画像を個人のSlackに送信します。ランチから帰ってきた人がすぐにレシートを送信できるよう、オフィスの出入口付近2か所に設置しています。 異才ランチ後の経費精算では、経費申請の際にレシートの画像を登録する必要があります。その際、入力の都合上PCでの申請が便利なため、一度手持ちのスマートフォン等でレシートの写真を撮り、Slack等で自分宛てに共有している人が複数いました。この手順をもっと手軽に行えないか、ということで生まれたのがこの「Receipt Sender」です。 Receipt Senderを利用したレシート送信は以下のような流れです。 1. 顔認証ログイン 2. レシート撮影 3. レシート送信 以下で Receipt Sender の利用方法をご紹介します。 ~利用方法~ 1. 「始める」ボタンから顔認証を実施 2. 本人であることを確認し、「レシートの撮影に進む」ボタンからレシート画像を撮影 3. 撮影した画像を確認し、「DMに送信する」ボタンからSlackへ送信 4. Slackに画像が届いていることを確認 デバイス機能の決定まで デバイスの具体的な機能や活用方法には悩みました。どのようなプロダクトを作っていきたいかのアイデア出しの時点においても、デバイスをどう活用するのか?を念頭に置いて考える必要があり、なかなかアイデアが定まらない一因となっていました。 アイデアが固まり、デバイスの用途は「レシート送信から経費申請までの手間を減らす」ものを作ると決まりました。当初の計画では、経費精算サービスと連携して、レシートの送信から申請までをスムーズに行えるよう整備することを考えました。 しかし、いざ社内で相談してみると、サービスとの連携はNGという結果に…。経費に関係し、セキュリティ面も考えての結果だったため、当初より範囲を小さくして開発することとなりました。そこで、ランチから帰ってきてすぐにレシートの送信ができるだけでも申請の手間が減ると考え、その機能を作成しました。 ただレシートを送信する機能だけではなく、デバイスとして設置する価値を高めたほうがよいとのご指摘もありました。どのように活用するかを考えた結果、トップページにおいて累計・月間それぞれのコネクト数を表示し、どの程度使われているのかを知ることができるように工夫しました。 これにより、isai connect の状況を社員の方が簡単に見れるようになり、興味を持っていただくきっかけを作ることができたのではないかと考えています。 開発上の苦労・工夫点 今回のデバイス開発では、実装の手軽さから Python を選択しました。GUIの作成は tkinter を使用しています。 2台のカメラの制御 図のように、Receipt Sender では、顔認証用のカメラ(市販のUSB-Webカメラ)と、レシート撮影用のカメラ(RaspberryPi用カメラモジュール)の2台のカメラを同時に使用しています。 1つのアプリ内でこれらのカメラを別々で動作させる際、顔認証用のカメラ映像は映らないがレシート撮影用のカメラ映像は映る…などの問題が生じました。 各カメラの映像を扱うのに、顔認証用ではOpenCV、レシート撮影用では picamera2 および libcamera と別々のライブラリを使用しており、複雑化していた点も要因の一つでした。 最終的には、カメラ毎にスレッドを割り当てて処理することで解決しました。 顔認証 顔認証の機能を実装するにあたり、2023年度の新卒エンジニア研修で開発された「librarian」の顔認証用APIを利用させてもらうことにしました。顔認証の実装となると大きく時間もかかるため、23卒の先輩方に利用させてほしい旨お伝えしたところ快く許諾してくださいました。 結果として、先輩から我々へと新卒エンジニア研修の成果が繋がる非常に良い要素だったのではないかと思っています。 一方、顔認証の部分では、複数人で連続で利用する際、操作している人ではなくその前に操作した人として認証されてしまう不具合もありました。下図に示す通り、顔認証画面からの画面遷移時にその時点でのカメラ画像が保持されたままになっており、再度顔認証画面を開いた際に保持された画像が一瞬表示されてしまうことが原因でした。 この不具合に対し、顔認証の処理を走らせる間隔を調整してみるなど様々試しながら修正を行いました。時間はかかってしまったものの、最終的には顔認証画面遷移時に明示的に認証情報をリセットすることで解決しました。 専用のケース作成 社内に設置するにあたり、RaspberryPi本体を隠しつつレシート撮影用カメラを固定するケースが市販で存在しなかったため、プラ板を用いて自作しました。本体に合う大きさに切って張り合わせるだけの単純な作業ではありましたが、ぴったり合うものを作成でき、むき出しのまま置くことを防げています。 今後の展望 今後は、常時稼働していることを活かし、利用されていないときは社内への周知事項を表示させるデジタルサイネージのような機能を開発することを考えています。また、このデバイスの価値を最大限高めるには、やはり経費申請をより簡単に行えるよう改善していく必要があると思っております。 最後に 私自身、チーム開発の経験がなく、プログラミングも研究で扱った程度(しかもFortranのみ)といった状態でした。技術的な不安が多くある中、必死に勉強しながら同期のメンバーや先輩の社員の皆様にもご協力いただき、最終的にはデバイスの開発部分の多くを実装することができました。デバイス以外にもフロント分野に挑戦することもでき、未経験でも多くの経験を積める有意義な研修であったと感じています。
アバター
この記事は Safie Engineers' Blog! Advent Calendar 6日目の記事です。 はじめに  こんにちは。第2開発部でフロントエンドエンジニアをしている東條です。今回は、2024年新卒エンジニア研修におけるインフラ分野の開発についてお話ししたいと思います。 はじめに セーフィーでの2024年新卒エンジニア研修と作ったプロダクトの紹介 導入 定期実行について バージョン更新とメンテナンスについて バージョンが更新されているのかどうかが判断できない バージョン更新中にアクセスするとエラーになる Slackへの通知が確認できない 感想 セーフィーでの2024年新卒エンジニア研修と作ったプロダクトの紹介  セーフィーでは全体研修後、約3ヶ月のエンジニア研修があり、エンジニアとしての基礎を学びつつ、社内課題を解決するプロダクトを開発しました。課題選定から開発言語、体制まで全て自分たちで決める形式で、私たちは「isai connect」を開発しました。これは、他部署の方とランチに行くと会社がランチ代を負担してくれる「異才ランチ」制度をより活用し、活発化を図るためのプロダクトです。詳しくは以下の記事でご覧ください。 新卒研修の紹介とチーム開発前にやったこと 2024年新卒エンジニア研修-アジャイル開発編 2024年新卒エンジニア研修-isai connectについて 2024年新卒エンジニア研修-isai connect開発のアウトプット_サーバーサイド 2024年新卒エンジニア研修-フロントエンド開発編 2024年新卒エンジニア研修-インフラ構築編 ←本記事 2024年新卒エンジニア研修-isai connect開発のアウトプット_デバイス編 2024年新卒エンジニア研修-新卒研修の成果発表とその後 導入  今回、個人としてはじめて IaC( Infrastructure as a Code ) によるインフラ構築を体験しました。使用したツールは Terraform です。そもそも記法やどんな仕組みで動いているのかも知らなかったため、他のインターン生がインターンのときに書いていたコードや公式のチュートリアルのコードとにらめっこしながら概要を把握していきました。  最終的な全体構成としては、 フロントエンドアプリ S3 にビルドしたファイル群を配置 CloudFront から配信 APIサーバー ECS Fargate でコンテナを立ち上げ DB Aurora MySQL のようになっています。 AWS のインフラ構成図  最初は Single AZ で組んでいたのですが、インフラの構築をしている時期にたまたま AWS の方が入門者向けにハンズオン形式で講義してくださる貴重な機会があり( https://engineers.safie.link/entry/safie_aws_starters_report )、そのなかで Multi AZ 構造をとることで可用性を担保できると教えていただいたので早速取り入れました。  余談ですが、AWS の DB 系の Multi AZ 構成では Writer (書き込み専用)と Reader (読み取り専用)が別れていて完全な2台構成になっていないということを初めて知りました。書き込みが複数の AZ で発生すると一貫性が崩れるので当たり前といえば当たり前ですが賢いですね。Writer が死ぬと Reader のうち1台が Writer に昇格するのは動物の生存本能みたいでとても合理的でおもしろい仕組みだと感じました。  この記事内では、インフラの構築および運用の中で工夫した点や苦労した点についていくつか紹介させていただきたいと思います。 定期実行について  24新卒チーム内で機能開発を進めていく中で、実際にコネクトしてお誘いのメッセージをおくったはいいものの返事をくれなかったときはどうすればいいのかという問題が浮き彫りになりました。ここで、3日経ったところで自動でキャンセルする機能の開発を行うことになりました。API のサーバーの機能的には、定期的に DB を見てコネクトの作成日から3日経っているかを判定してキャンセル処理をすればよいのですが、本番環境で定期実行をどうするかに結構悩みました。  最初思い浮かんだのは cron スケジュールですが、そもそも Fargate では Linux 自体を起動しているわけではなく Python:3.11-slim のイメージを起動していますし、今後オートスケーリングなどをした場合は無駄に複数回処理を回すことになりバグが発生する可能性もあり却下しました。  そこで、AWS のサービス自体でなんとかできないかと色々調べ回った結果2つ選択肢の目星をつけました。 Lambda を使用して Aurora MySQL を直接操作する Event Bridge Scheduler で ECS タスクを定期実行する  最終的には EventBridge Scheduler で ECS タスクを定期実行する方針で決めました。理由としては、学習コストが少ないことです。これは、チーム内のスケジュール的な問題ではありますが、この定期実行のタスクに取り掛かったのが最終のスプリントであったため、学習コストを抑えて短期で実行可能な状態まで持っていく必要がありました。  実際の実装としては単純なもので、API サーバーで定期実行用の API エンドポイントを用意して定期実行 ECS の中では curl イメージを使用してただその API を叩いています。このような実装にした理由は、開発において API サーバーとキャンセル機構が分離すると保守性が下がってしまうためです。 バージョン更新とメンテナンスについて  今回のインフラ構築では、アプリケーションの特性上アクセス頻度が高くないことと、集中した開発が研修中だけであることから、AWS のコストを抑えるためステージング環境を用意せず本番環境のみの構成としています。その中で困ったことが3点ありました。 バージョンが更新されているのかどうかが判断できない バージョン更新中にアクセスするとエラーになる Slack への通知が確認できない  それぞれどのように解決したかをご紹介します。 バージョンが更新されているのかどうかが判断できない  これはステージング環境があっても起こることだとは思うのですが、イメージやファイルをあげてアップデートしてもそれが反映されているのか、エラーで反映されていないのか、が判断できませんでした。フロントエンドだとデザインの修正や機能の修正が目に見えるのである程度問題はないのですが、とくにサーバーサイドのバグ修正や DB のスキーマ修正などは API を叩くまでは判断できないためデプロイ時に判断できる仕組みが必要でした。  対策としては、ビルド時にバージョンを入れ込む仕組みを導入しました。デプロイする際に CI で自動で付与していたバージョン( vx.x.x )を指定してビルド&デプロイすることで外部から簡単にバージョンを確認できるようにしました。  具体的には、フロントエンドではビルドするコマンドにバージョンを渡すことで meta タグにバージョンが埋め込まれるようにしました。バックエンドではイメージのビルド時に Dockerfile で環境変数を ARG と ENV を用いて固定することで Swagger UI に表示し、それぞれバージョンの表示を実現しています。以下画像は v1.6.0 状態を確認した際のものです。 フロントエンド バックエンド  このあたりはまだデプロイを含めて自動化できていないため、今後の課題として CI/CD を充実させたいです。 バージョン更新中にアクセスするとエラーになる  フロントエンドのアプリケーションはキャッシュを削除しない限り以前のバージョンが配信されますし、バックエンドも更新をかけて新しいコンテナが起動してから置き換わるのでそれぞれがエラーを吐くことはないのですが、デプロイ自体のラグが発生するためフロントエンドで叩いていた API が新しいパラメータを要求するようになっていたり、逆も然りが置きます。  そこで対策としてメンテナンス期間を導入しました。想像つきやすいのは銀行系のアプリなどである「◯月◯日◯時から◯時はメンテナンスのため一部機能がご利用できない可能性があります」だと思います。AWS の ALB に固定 503 Service Unavailable エラーを返すルールをメンテナンス中のみ追加し、フロントエンド側は 503 Error を返却されたときにメンテナンスページを開くように実装することでデプロイ中の数分間のみサービスを停止しています。 メンテナンス中に表示される画面 Slackへの通知が確認できない  本番環境の API を叩くと実際に DM が届いてしまうので、Slack からのアクションを確認できないという問題が発生しました。プレリリース前の開発中はテスト用の Slack チャンネルを作成することで実際に DM を飛ばすことなく確認できたのですが、本番環境ではそうはいかないので代替案を考える必要がありました。  色々考えた結果、最終本番環境に Slack App のテスト環境を作りました。具体的には、Slack App を開発検証用に DM 権限を制限した状態で作成し、図のように開発検証用の Slack App には本番環境のテスト用エンドポイントを指定、テスト用エンドポイントへのリクエストボディをそのままテスト用チャンネルに送信するように実装しました。こうすることでテスト用チャンネルに送られてきたリクエストボディをローカル環境で立ち上げている API サーバーに送信することができます。これによりで Slack のアクションを確認することが可能になりました。(ただし、参考として ngrok などを使ってローカル環境で Slack App 自体をモックすることは可能なようです) Slack通知のテスト環境概念図 感想  今こうして振り返るとこんな感じに構築していたらもっと楽だったかもしれない、今ならこうするといった反省点が山盛りではあるのですが、個人開発でも触ってこなかったインフラの分野についてチーム開発を通して試行錯誤しながら触れることができたのは良い経験だと考えています。また、新卒でのチーム開発を通して配属されたあとも未だに一緒にお昼ごはんを食べているくらい仲が良くなったので、何かあったときに気軽に相談できる仲間を社内に作れたという点はとても重要でした。
アバター
この記事は Safie Engineers' Blog! Advent Calendar  5日目の記事です。 自己紹介 こんにちは。セーフィー株式会社 開発本部所属の佐々木 大翔(ささき ひろと)と申します。今回は、我々が行った2024年度新卒エンジニア研修における、フロントエンド開発についてお話ししたいと思います。 自己紹介 エンジニア研修と開発したプロダクトについて 活動内容 画面定義 画面実装 使用技術 工夫した点 テストコード実装 テスト方針 テストツール 気をつけたこと・学んだこと 試行錯誤した部分 改善例 トップ画面の改善 プログレスバーの追加 アプリのフロントエンド開発をしてみて エンジニア研修と開発したプロダクトについて セーフィーでは全体研修後、約3ヶ月のエンジニア研修があり、エンジニアとしての基礎を学びつつ、社内課題を解決するプロダクトを開発しました。課題選定から開発言語、体制まで全て自分たちで決める形式で、私たちは「isai connect」を開発しました。これは、他部署の方とランチに行くと会社がランチ代を負担してくれる「異才ランチ」制度をより活用し、活発化を図るためのプロダクトです。詳しくは以下の記事でご覧ください。 新卒研修の紹介とチーム開発前にやったこと 2024年新卒エンジニア研修-アジャイル開発編 2024年新卒エンジニア研修-isai connectについて 2024年新卒エンジニア研修-isai connect開発のアウトプット_サーバーサイド 2024年新卒エンジニア研修-フロントエンド開発編 ←本記事 2024年新卒エンジニア研修-インフラ構築編 2024年新卒エンジニア研修-isai connect開発のアウトプット_デバイス編 2024年新卒エンジニア研修-新卒研修の成果発表とその後 活動内容 今回のフロントエンド開発で行ったことは以下の通りです。 画面定義 実装 テストコード実装 以上の工程について、それぞれ説明していきます。 画面定義 ここでは、Figmaを用いてアプリ内のページ遷移や各ページのレイアウト、UI・UXデザインを定義した画面仕様書の作成を行いました。 フロントエンド開発の担当者は決まっていたものの、画面仕様書を作成した際にはチームメンバー全員で確認を行うなどして、チーム内できちんと合意をとった上で画面定義を行いました。 また、我々の開発はアジャイル開発をベースにしていたので、スプリントごとに画面定義を行いました。アジャイル開発については こちらの記事 をご覧ください。 isai-connect-画面デザイン 画面実装 制作した画面仕様書をもとに、コーディングを行いました。 使用技術 今回の実装で使用したものは、以下の通りとなっております。 プログラミング言語・・・TypeScript フレームワーク・・・React ビルドツール・・・Vite UIライブラリ・・・Material UI コード整形関連ツール・・・ESlint, Prettier 基本的に、ドキュメント量が豊富であり、サポートが現在も継続的に行われているツールを採用しました。また、実際にセーフィーで活用されている言語やツールを用いることで、配属後の学習コストを下げる狙いもありました。 工夫した点 Figmaで定義したフォントサイズやコンポーネントが画面上に反映されやすくなるよう、Figmaの設定に忠実に倣って、Material UIのコンポーネントのテーマを定義しました。 例えば、上の画像に定義されている黄色の「デフォルトボタン」では、ColorにSecondary、VariantにContainedが定義されています。 isai-connect-ボタンデザイン isai-connect-デザイン設定 この設定をコード上では以下のように定義しました。これによりコンポーネントに”color=’Secondary’”、”variant=’contained’”というような形で変数を指定するだけで、この黄色のボタンをFigmaの定義通りに表現することができます。 components : { MuiButton : { variants : [ { props : { size : "small" } , style : { fontSize : 10 } } , { props : { size : "medium" } , style : { fontSize : 16 } } , { props : { size : "large" } , style : { fontSize : 24 } } ] } } palette: { text: { primary: "#333" }, primary: { main: "#FFAD36", contrastText: "#fff" }, secondary: { main: "#2981C0", contrastText: "#fff" }, error: { main: "#D02F48", contrastText: "#fff" }, shadow: { main: SHADOW_COLOR }, disable: { main: "#757575" } } テストコード実装 テスト方針 ページごとに単体テストコードを実装しました。 アプリ内のあるページを実装した人が、テストコードも合わせて実装するという方針で進めました。 今回のテストコード実装では 主に画面に情報がきちんと表示されているか ユーザーの操作をテスト内で模擬し、正しい振る舞いが画面上でできているか といった、ユーザー目線に近い観点でテストコードを実装しました。 テストツール テストコード実装の際に使用したツールは以下の通りです。 Jest testing-library/react 気をつけたこと・学んだこと きちんとテストコードを書いたり、チーム内でテスト方針を考えたりすること自体初めてだったので、とても学びが多い部分だったと感じております。 APIとの通信が絡む処理については、サービスの共通モックをあらかじめ作ることで、テストコード実装者によって、API処理周りの処理の書き方にばらつきが出ないようにしました。 学んだこととしては、テストコード実装初心者だった我々にとって、Jestやtesting-library/reactで提供されている関数や概念を理解するのに苦労しました。この仕組みはどのように使われ、なぜ必要なのかを一つずつ学んでいきました。 実際に私たちが実装したテストコードの一例をお見せします。 test ( "slackにURLを送信するテスト" , async () => { renderDOM ( "register" ) const emailInput = screen . getByLabelText (/ メールアドレス /) const registerButton = screen . getByRole ( "button" , { name : / 登録 / }) // 入力 await userEvent . type ( emailInput , "test@example.com" ) // 登録実行 await userEvent . click ( registerButton ) await waitFor (() => { expect ( screen . getByText (/ まだ登録は完了していません! /)) . toBeInTheDocument () }) }) test ( "slackにURLを送信するエラー" , async () => { mockRejectedValueOnce ( userService , "sendPasswordRegisterNotification" ) renderDOM ( "register" ) const emailInput = screen . getByLabelText (/ メールアドレス /) const registerButton = screen . getByRole ( "button" , { name : / 登録 / }) await userEvent . type ( emailInput , "test@example.com" ) await userEvent . click ( registerButton ) await waitFor (() => { expect ( screen . getByText (/ 登録できませんでした。再度試してください。 /)) . toBeInTheDocument () }) }) こちらのコードはランチ相手が決定し、Slackに招待を送る部分の処理のテストコードです。正常系でテストを行った後に、異常系やレアケースもきちんとテストするようにしました。 何をテストし、どのような期待値が求められるのかをきちんとコード内で明文化することを意識しました。このコードに関して言うと、ユーザーのタイプ操作やクリック操作は非同期処理になるため、適切にawaitを仕込む必要性がありました。また、ユーザー操作の結果を受けて実行される処理に関しても、ユーザー操作の非同期処理を待ってから処理が走るように設定しなければなりませんでした。この設定を怠ると、非同期処理の部分だけ適切に実行されずに空回りし、望まないテスト結果につながってしまいます。 試行錯誤した部分 上述のように、フロントエンド開発といってもいろいろな工程があります。 特にこの中で一番試行錯誤した点を上げるとすれば、UI・UXデザインだと感じております。 「ユーザーが直感的に使えて、ストレスを感じさせないようなページ遷移、UIデザイン、誘導を行うにはどうすればいいのか」 このテーマを常に意識しながら画面定義を行っていたのですが、毎回スプリントレビューで上司の方々からご指摘をいただいておりました。 主にいただいていたご指摘としては、 同じ確認を何度もさせているので、ユーザーにとってストレス ボタンを押した後の結果が推測できない パーツの配置、サイズにどんなコンセプトがあるのかが考慮されていない などがありました。 改善例 トップ画面の改善 トップ画面からランダムマッチングを選択した際、もともとは以下のような画面レイアウトと遷移を定義していました。 isai-connect-画面遷移 こちらの画面遷移についてご説明します。まず、左側にあるトップ画面に「異才を探す」という黄色いボタンがあります。このボタンをクリックすることで、真ん中に表示されている画面に遷移します。左側にある「ランダムに異才をさがす」というボタンを押すことで、画像右側にある確認画面へと遷移します。 しかし、これでは「異才を探す」という選択を、ユーザーに3回もさせてしまうことになり、明らかに冗長な工程だとわかります。 そこで、操作回数を減らしつつ、ユーザーが操作内容を直感で推測できるように改良したものが、以下の画像になります。 isai-connect-マッチングの選択画面 マッチング方法の選択作業をページ一つにまとめ、ボタンを押せばどのような処理が走るのかが一目でわかるような見た目にしました。 また、上二つのボタンと下の「部署を選んで」ボタンにも工夫した点があります。上二つのボタンは、押下後にすぐにマッチングが走る仕組みです。人数は異なりますが、「すぐにマッチングが走る」というコンセプトが一致しているため、ボタンのサイズや形状を統一させています。対して、下の「部署を選んで」ボタンは、ボタン押下後に部署の選択画面に遷移するため、すぐにマッチングが走るというわけではありません。このようにコンセプトが上の二つのボタンとは異なるため、形状とサイズに違いを持たせました。 プログレスバーの追加 ユーザーが実際にマッチングを行い、マッチングが終わった後の結果表示からSlackへのメッセージ送信完了への画面遷移に関しても、改善前は以下のように定義していました。 isai-connect-プログレスバー実装前 「トップ画面の改善」の節でお見せした改善前の画面遷移と合わせて見てみます。私たち開発側からすれば、この遷移で問題ないように見えてしまいますが、この状態でリリースされたアプリを初めて触るユーザーは違います。この画面遷移のままだと、ユーザーが何かボタンを押した後の結果が、実際に遷移されてからでないとわかりません。 この問題を解決するために導入したのが、画面上部に表示するプログレスバーです。プログレスバーを導入することで、ある操作をした後にどういう状態になるのかが一目でわかるようになりました。 isai-connect-プログレスバー実装後 アプリのフロントエンド開発をしてみて 私たちは常日頃からアプリケーションを利用しています。しかし、いざユーザー視点でアプリを作るとなると、日ごろからアプリを利用している身であるにもかかわらず、考えが及ばなかったり、意思決定に時間がかかったりする場面がたくさんありました。フロントエンド開発に今後も携わる身として、ユーザーにストレスを与えず、直感で機能・場所・状態を即座に推測できるようなUI/UXデザインができるように、日々精進していきたいと思います。私たちが開発したアプリを通じて、部署の垣根を超えたコミュニケーションが、社内でより活発になれば幸いです。 最後までご覧いただきありがとうございました。
アバター
この記事は Safie Engineers' Blog! Advent Calendar 4日目の記事です。 はじめに  こんにちは。第3開発部でエンジニアをしている伊東です。今回は2024年新卒エンジニア研修における、バックエンド分野の開発についてお話しします。 はじめに セーフィーでの2024年新卒エンジニア研修と作ったプロダクトの紹介 機能 設計 ER図 シーケンス図 API仕様書 実装 使用技術 ディレクトリ構成 認証 工夫したポイント おわりに セーフィーでの2024年新卒エンジニア研修と作ったプロダクトの紹介  セーフィーでは全体研修後、約3ヶ月のエンジニア研修があり、エンジニアとしての基礎を学びつつ、社内課題を解決するプロダクトを開発しました。課題選定から開発言語、体制まで全て自分たちで決める形式で、私たちは「isai connect」を開発しました。 これは、他部署の方とランチに行くと会社がランチ代を負担してくれる「異才ランチ」制度をより活用し、活発化を図るためのプロダクトです。 詳しくは以下の記事でご覧ください。 新卒研修の紹介とチーム開発前にやったこと 2024年新卒エンジニア研修-アジャイル開発編 2024年新卒エンジニア研修-isai connectについて 2024年新卒エンジニア研修-isai connect開発のアウトプット_サーバーサイド ←本記事 2024年新卒エンジニア研修-フロントエンド開発編 2024年新卒エンジニア研修-インフラ構築編 2024年新卒エンジニア研修-isai connect開発のアウトプット_デバイス編 2024年新卒エンジニア研修-新卒研修の成果発表とその後 機能  isai connectで実装した主要機能は以下の通りです。isai connect管理者にはユーザ管理機能、ユーザにはレコメンド機能とコネクト機能を提供しています。 ユーザ管理 月一で従業員名簿からユーザを作成・更新・削除する機能です。isai connectに登録していないユーザもレコメンドし、コネクトさせる必要があるため従業員名簿からユーザを一括登録しています。 レコメンド 一緒にランチするメンバーを指定したチームからランダムに提示してくれる機能です。「全従業員が保持している属性」「属性判別が容易」の2観点からチーム指定をまず実装しました。今後は様々な属性を指定できるようにしていきます。 コネクト レコメンドされたメンバーに対してランチを誘うSlack DMを送信し、ランチ参加者だけのSlackグループを作成する機能です。社内の主なコミュニケーションツールであるSlackのDM機能を使用することで、メッセージの見逃しリスクを低減し、スムーズな意思決定を促進しています。 設計  isai connectのバックエンド実装を設計書を用いて説明します。 ER図  以下にisai connect用のER図を示します。  各テーブルが管理している情報は以下の通りです。 ユーザ情報 部門情報 部署情報 グループ情報 コネクト実績情報 ユーザに関連する製品情報 コネクト状況の情報 コネクト参加者の情報  コネクト実績とユーザに関連する製品情報を管理するテーブルは、ユーザと多対多の関係になることから、中間テーブルを使用して効率的に管理できるようにしています。 シーケンス図  開発当初は処理ロジックを明確にするためシーケンス図を作成していましたが、API仕様書をフロントエンドと協議して作成する際に実装ロジックが明確になり、共通理解が生まれるため、途中から作成されなくなりました。開発時のシーケンス図の利用頻度は高くはありませんでしたが、参考としてレコメンドからコネクトまでのシーケンス図を掲載します。 API仕様書  1〜3スプリントでは、認識の齟齬を生まないために予めフロントエンドと協議してAPI仕様を策定し、仕様書としてドキュメント化していました。4スプリント目では協議とドキュメント化の時間削減を目的に、バックエンドが定義したAPI仕様をSwagger UIを通じてフロントエンドに渡し、必要であれば都度修正するという試みを行いました。しかしながら、この試みは都度修正の特性上、フロントエンド・バックエンド双方に手戻りを多く強いることになり、結果として多大な時間を浪費することになりました。Swagger UIをドキュメントの代替として用いたことは間違ったアプローチではありませんでしたが、事前の十分な協議なしにこの方法を導入したことが問題でした。  以下に最終的に作成したisai connectのAPI仕様書の一部を示します。  isai/random/は、部門及び部署をクエリパラメータとして指定することで、ランダムなユーザを一人取得するためのAPIです。また、isai/connectは、ホストユーザーと1~3人のゲストユーザーのIDを受け取り、コネクトを行うためのAPIです。 実装  isai connectのバックエンドの実装方法について説明します。 使用技術  配属後の学習コストを減らす目的で、実際にセーフィーで活用されている言語及びフレームワークを選定しました。使用言語、フレームワーク、主要なライブラリは以下の通りです。 言語 Python フレームワーク FastAPI ライブラリ Pydantic SQLAlchemy Alembic ディレクトリ構成  バックエンドの1層目の主要ディレクトリ及びファイルを以下に示します。 app/ ├── connect_db.py ├── cruds/ ├── init_db.py ├── main.py ├── models/ ├── routers/ ├── schemas/ ├── tests/ ├── util/  このディレクトリ構成で開発を進めた結果、ビジネスロジックがcrudsに集中してしまい、ファイルの肥大化と難読化が進行、重複処理が増加するという課題が生じました。この課題を解決するため、今後の開発ではディレクトリ構成の見直しが必要だと考えています。改善策としては、crudsディレクトリ内では純粋なデータベース操作のみを許容し、ビジネスロジックは新たに作成するservicesディレクトリに移動、共通処理の抽出などが挙げられます。これらの変更により、コードの構造が明確になり、保守性と可読性の向上が期待できます。 認証  isai connectの認証では、セキュリティ面と実装の容易さから、OAuth2をベースに、JWTを認証トークンとする方式にしています。基本的な実装はFastAPI公式に従っていますが、トークンが漏洩した場合のリスクを軽減を目的に、追加でリフレッシュトークンを導入しています。また、トークンの保存にはHttpOnlyおよびSecure属性を持つCookieを使用しています。 工夫したポイント  isai connectでは、ユーザの情報取得やDM送信のためにSlack APIを使用しています。これを逐次処理でおこなうと相当な時間を要するため、処理を並行化やマルチスレッド化することが検討されました。並行化とマルチスレッド化を比較したところ、処理時間平均に大きな差異はありませんでしたが、最小と最大の処理時間の差が並行化した方が少く、安定した性能であったため、並行化が採用されました。結果として、DM送信の処理時間を逐次処理したときと比較して2.6倍ほど早めることができました。 おわりに  筆者は、インターンシップで個人でのシステム開発経験を積む機会がありましたが、チームとしてフロントエンドやバックエンドに分かれての開発経験は限られていました。個人開発の際には、設計のドキュメント化を軽視する傾向がありましたが、チーム開発を経験した現在では、チーム内共有の観点からその重要性を強く認識するようになりました。現在所属する部署では、実装だけでなく、事前の調査や事後の評価など、実装の前後のプロセスも成果物の一つとして重視されています。そのため、配属前にドキュメント化の重要性に対する意識を高められたことは、非常に有益でした。  今後、isai connectは開発フェーズから運用フェーズに移行しますが、システムの拡張を継続し、社内コミュニケーションを活発にしたいと考えています。  最後までご覧いただき、ありがとうございました。
アバター
この記事は Safie Engineers' Blog! Advent Calendar 3日目の記事です はじめに こんにちは、第1開発部でサーバーサイドエンジニアをしている坂上(さかうえ)です。今回は2024年新卒エンジニア研修で開発したプロダクト「isai connect」について、その背景や機能を紹介します。 はじめに isai connectを作った経緯 ターゲットと課題と解決策 開発を始める前のエピソード isai connectの機能紹介 異才ランチに誘う人を探す機能 SlackのグループDM自動作成機能 コネクト履歴機能 コネクト実績機能 デバイス isai connectを育てていく isai connectを作った経緯 2024年新卒エンジニア研修では、「社内課題を解決するプロダクト開発」というテーマについて取り組みました。これは、セーフィーの中で抱えている課題を見つけ、その解決に向けて、要件定義、設計、開発から運用まで一気通貫して取り組むというものです。 こうして生まれたのがisai connectです。以降では、本プロダクトの開発に着手するまでに行なったセーフィーの中で抱えている課題、ターゲットと解決策の模索、そして、それを解決するisai connectの機能について、紹介します。 新卒研修の紹介とチーム開発前にやったこと 2024年新卒エンジニア研修-アジャイル開発編 2024年新卒エンジニア研修-isai connectについて ←本記事 2024年新卒エンジニア研修-isai connect開発のアウトプット_サーバーサイド 2024年新卒エンジニア研修-フロントエンド開発編 2024年新卒エンジニア研修-インフラ構築編 2024年新卒エンジニア研修-isai connect開発のアウトプット_デバイス編 2024年新卒エンジニア研修-新卒研修の成果発表とその後 ターゲットと課題と解決策 まず、会社における「不」を探るため、以下のプロセスを行いました。 自身の体験や感じたことをリストアップし、共感度の高いものを優先 ユーザーインタビューを実施し、社員の生の声を収集 そこで浮かび上がったのが、セーフィーの福利厚生の1つである異才ランチの課題です。 異才ランチは、他部署の社員とのランチ代を月に2回支給される制度です。新たなアイデアの創出や他部署を巻き込むきっかけとなったり、相互理解に繋がったりといった目的があります。しかし、ユーザーインタビューを通して、以下のような意見がありました。 異才ランチを使えていますか? ついつい月滅になってしまって使えていない できれば知らない人と使いたいけれど誘えない 異才ランチでこうであったら良いなと思う点はありますか? 同じコミュニティ内(開発本部内で仲の良い人など)で固まってしまうことが多いので、他の人と行くきっかけが欲しい このように、社員の中には、誰を選んだら良いかがわからない場合や、見知った仲の方ばかりと行く場合などがあることがわかりました。これは、本来の目的に沿った異才ランチの活用に障壁を感じている方がいるということもできます。 そこで、ターゲットと課題、解決策を以下のように定めました。 ターゲット 異才ランチを使いたいが、誰を誘おうか迷っていたり、そこに障壁を感じている社員 課題 異才ランチを行う際、誰を誘うかやきっかけ作りが利用者にとって難しく感じられることがある 解決策 異才ランチを利用する社員をマッチングするシステムを構築し、異才ランチの実現をサポートする 開発を始める前のエピソード ターゲット、課題と解決策が定まったところで、いざ設計や開発が始まると思いきや、ここで社会人ならではの経験をしました。それは、セーフィーのCTOである森本さんから承認を得るプロセスです。 本プロダクトの開発には、会社の予算が必要でした。そのため、必要なコスト(備品やインフラ料金)を見積もり、プロダクトの価値やメリットを説明する資料を作成しました。7人の想いを込めて、森本さんに直接交渉を行いました。最終的に、無事に賛同していただき、開発のための予算を獲得することができました。この機会を通じて、技術的な関心に留まらず、プロダクトが持つ価値が実際にどのような影響を与えるのかを深く考える貴重な学びを得ることができました。これらを踏まえてisai connectはとても思い入れの深いプロダクトになっています。 isai connectの機能紹介 異才ランチに誘う人を探す機能 課題に挙げた異才ランチに誘うキッカケ作りをより簡単に、より気軽にするために、isai connectでは、3つの方法で異才ランチに誘う機能があります。 3人まとめて 他部署の社員の方々を3人ランダムに選ぶことができます。ボタン1クリックで、気軽に誘うことを目的にこの機能を作りました。 1人ずつ 1人ずつランダムに選ぶことができます。ユーザーが希望する人数でランチに行けるように、段階的に招待する人数を増やせるような機能を作りました。 部署を選んで 部署を選んで、その中から1人ずつランダムに選ぶことができる機能です。興味がある、または、知りたい部署があるユーザーのためにこの機能を作りました。 SlackのグループDM自動作成機能 異才ランチに誘う人を探したのちに、招待メッセージをSlackで送ることができます。異才ランチを始める最初のSlackメッセージを自動化することで、より気軽に誘えるきっかけにしました。また、誘われた人も気軽にお誘いに応えられるようにしました。 誘う人のSlack画面誘った人が、誰に誘ったのかを改めて確認できると同時に、Notion自己紹介のリンクを載せました。ランチに行く前にどんな人なのかを手軽に確認できるようになっています。 誘われた人のSlack画面 誘われた人が、行きましょう😀、か、ごめんなさい💦ボタンを押すことで、誘った人にランチに行けるかどうかのメッセージが飛ぶようになっています。 異才ランチが成立した場合のSlack画面異才ランチが成立すると、自動でグループDMが作成され、参加者に成立したことをお知らせするメッセージが送られます。また、ランチが終了した後に「いってきた」ボタンを押すと、経費申請の手順と必要な情報がSlackでまとめて確認できるようになります。 異才ランチが不成立だった場合のSlack画面誘われた人全員が異才ランチに行くことができなかった場合に、誘った人にその旨を通知する機能です。 コネクト履歴機能 今まで一緒に異才ランチに行ったメンバーや、現在進行中の異才ランチのお誘い状況を一覧で確認できる機能です。これによって、24新卒メンバーの自身の体験にあった、どの方といつ異才ランチに行ったのかが一目瞭然になっています。 コネクト実績機能 異才ランチを利用した回数や、一緒に行ったメンバーの部署の種類の数に応じて、実績を付与する機能です。これは、異才ランチの利用をより楽しくしてもらえるように作りました。この実績は今後増やして行く予定です。 デバイス Webアプリケーションだけでなく、専用デバイスも開発しました。このデバイスは、顔認証後にユーザーのSlackにレシート画像を直接送信する機能を備えています。これにより、異才ランチ後の経費申請で、スマホでレシートを撮影してPCに送る手間を省けます。ユーザーインタビューで挙がった「経費申請の手間を減らしたい」という要望に応える仕組みです。 さらに、デバイスの画面には、isai connectを通じて行われた異才ランチの月間利用数と累計利用数が表示されており、利用状況がリアルタイムで分かるようになっています。 isai connectを育てていく 様々なバックグラウンドを持った24新卒エンジニア7人が集まって、四苦八苦しながらこのisai connectを作りました。今後は、日々の業務と並行して、このプロダクトを運用するだけでなく、さらに成長させていきます。本記事は、プロダクトの説明に留まってしまいましたが、他の記事では、プロダクトを作る過程やチームの様子などを知ることができます。ぜひご覧ください。
アバター
この記事は Safie Engineers' Blog! Advent Calendar  2日目の記事です。 はじめに こんにちは!第1開発部でサーバーサイドエンジニアをしている古谷です! 今回は2024年新卒エンジニア研修で行った開発について開発体制の観点からお話しします! はじめに セーフィーでの2024年新卒エンジニア研修と作ったプロダクトの紹介 開発体制をアジャイル開発に決定 スクラムで意識したこと スクラムイベントでの工夫 ユーザーストーリーマッピング スプリントプランニング デイリースクラム スプリントレビュー レトロスペクティブ ポジティブ共有会 結果と感想 セーフィーでの2024年新卒エンジニア研修と作ったプロダクトの紹介 セーフィーでは全体研修後、約3ヶ月のエンジニア研修があり、エンジニアとしての基礎を学びつつ、社内課題を解決するプロダクトを開発しました。課題選定から開発言語、体制まで全て自分たちで決める形式で、私たちは「isai connect」を開発しました。これは、他部署の方とランチに行くと会社がランチ代を負担してくれる「異才ランチ」制度をより活用し、活発化を図るためのプロダクトです。詳しくは以下の記事でご覧ください。 新卒研修の紹介とチーム開発前にやったこと 2024年新卒エンジニア研修-アジャイル開発編 ←本記事 2024年新卒エンジニア研修-isai connectについて 2024年新卒エンジニア研修-isai connect開発のアウトプット_サーバーサイド 2024年新卒エンジニア研修-フロントエンド開発編 2024年新卒エンジニア研修-インフラ構築編 2024年新卒エンジニア研修-isai connect開発のアウトプット_デバイス編 2024年新卒エンジニア研修-新卒研修の成果発表とその後 開発体制をアジャイル開発に決定 開発は新卒エンジニア7人で行いました。開発体制を決める上でウォーターフォール開発かアジャイル開発にするかをチームで話し合い、悩んだ結果アジャイル開発のスクラムに決めました。決め手は新卒研修の目的の一つに「プロダクトが成長し続けることの重要性を知る」が設定されていたことです。3ヶ月という短い期間でプロダクトを成長させるという経験を積むためには、アジャイル開発のスクラムを用いて小さくリリースを繰り返すことが目的の達成に繋がると考えました。 スクラムで意識したこと 私はチームでスクラムを行っていく上でスクラムマスターというポジションでチームに貢献していました。スクラムマスターはチームで誰よりもスクラムに詳しい必要があり、チームにスクラムを浸透させる役割があります。私が意識したことは「一般的な基本のスクラムを実践すること」です。スクラムはよくチームに合わせてアレンジして使われることが多く、正解はないとされています。しかしチームではまだ誰もスクラムを実践したことはなかったためアレンジをする前にまずは基本を知るということを大切にしました。そのために、Udemyを用いてスクラムを勉強しチームに普及しました。今回はスクラムマスターとプロダクトオーナー(テックリードの方が役割としては近い)を役割としてチームで定め、スプリントは2週間で開発を進めました。また、スクラムを実践する上でカンバンも取り入れました。 スクラムイベントでの工夫 ここからはアジャイル開発のスクラムを実践する上での工夫についてお話しします。 ユーザーストーリーマッピング スクラムではスプリントという短い期間(今回は2週間)での開発を繰り返し何度もリリースをすることでプロダクトを作り上げていきます。異才ランチをよくするプロダクトを作ると決めた後、課題を解決するための機能に優先順位をつけるために図1のようなユーザーストーリーマッピングを作成しました。ユーザーストーリーマッピングでは「誰が・何を・なぜ」という型で課題を一つ一つの付箋に書き出し、時系列を横軸に優先度を縦軸に並べたものを作成します。開発する機能の優先順位をつけるための付箋に書き出す課題のちょうどいい粒度を見つけることが難しく、2回作り直しました。「何を」の項目に対して「異才ランチで誰を誘っていいかわからないことを解決する」というような粒度から「異才ランチを誘う相手をランダムで提案する」という機能により近い粒度で書くことで解決しました。始めはこのユーザーストーリーマッピングは意味あるのだろうかと不安になることもありましたが、途中からはスプリントプランニングをしていく上でなくてはならない存在になっていました。 図1 ユーザーストーリーマッピング スプリントプランニング スプリントプランニングは各スプリントの最初に行い、その2週間で何を達成するためにどのコア機能を作るのかをユーザーストーリーマッピングを元にチームで話し合います。まず始めにスプリントゴールを決め、次にそのスプリントゴールに必要なコア機能を取捨選択します。そして、各タスクにストーリーポイントを割り振り、チームのベロシティと比較し調整して完了です。図2はスプリントプランニング後のユーザーストーリーマッピングの一部です。スクラムイベントの中でスプリントプランニングが一番大変でした。7人のイメージしているプロダクトのイメージがそれぞれバラバラで合わせるために長い時間を使ってしまいました。スプリントプランニングの時間はスプリントが1ヶ月だと8時間ぐらいという目安があります。(参考: スクラムガイド )今回はスプリントが2週間なので半分の4時間ぐらいまでだと考えていたのですが、人数が7人と多かったことと、スプリントプランニングを適当にすると変なものが出来上がり2週間の意味がなくなってしまうという理由で時間が伸びても気にしないようにしていました。長い時は7時間以上かかることもありました。とはいえ話し合いに時間をかけすぎて実装の時間が無くなっては困ります。7人のイメージを合わせることに一番時間を使っていたので、その工夫として7人で図3のような簡易的な画面遷移図を作成するなどをしていました。この工夫をするまではイメージを合わせるのに時間がかかっていたり、イメージがずれていることに気付けなかったりということが多かったのですが、この工夫により話し合いがスムーズに進むようになりました。 図2 スプリントプランニング中のMiro 図3 簡易的な画面遷移図 デイリースクラム 毎朝30分ほどバーンダウンチャートを確認しながらスプリントが順調に進んでいるか問題点はないかということを全員で共有する場を作っていました。各メンバーが問題点を早期に共有できるように雑談を織り交ぜたりチェックインをしたりしながら話しやすい環境作りを意識しました。また、スクラムマスターから問題があるか聞くのではなく各メンバーから報告する形にすることで自分から報告するという癖を付けられるようにしました。 スプリントレビュー スプリントレビューでは2週間で開発したものをお披露目し、レビューを受けることで目的を解決できるものになっているかなどを確認しました。第3回目のスプリントレビューからは初めてisai connectを知る方も交えて行うことでより利用者の気持ちを知ることができました。第3回のスプリントレビューではコア機能に触れるまでクリック数が多すぎるという指摘を受けました。動作に説明をつけたいという理由で増やしており、コア機能までは5クリックほど必要でした。しかし、コア機能まで遠いとその分だけユーザーが離脱してしまう可能性が高くなります。最後にはコア機能に触れるまで最短2クリックでできるようになりプロダクトを改善させることができました。他にもスプリントレビューで受けたフィードバックを抜粋しておきます。 ローディングはワクワク感を強めるために一部長めにしてもいいのでは?(第2回スプリントレビュー) ホーム画面の余白が気になる(第3回スプリントレビュー) 日程調整機能があると嬉しい(第3回スプリントレビュー) UIは良くなったがUXはまだまだ改善の余地がある、slackのユーザーに通知が送られた後にユーザーが混乱してしまいそう(第3回スプリントレビュー) シャチのローディングのUIが素晴らしい(第4回スプリントレビュー) 自分たちのロゴはどのページでも表示するようにしよう(第4回スプリントレビュー) レトロスペクティブ レトロスペクティブでは図4のKPT法を用いて「継続すること・改善したいこと・挑戦したいこと」に分けて2週間の振り返りを行いました。今後のチーム開発をより良くするにはということを話し合う上で振り返りとなるとつい改善点ばかりに目を向けてしまいがちですが、KPT法を用いることで良かった点にも目を向けることができ気持ちのいい振り返りをすることができました。ここで出たTryはデイリースクラムで毎日確認し、意識できるように心がけました。 図4 KPT法 ポジティブ共有会 スクラムイベントとしてあるわけではありませんが、ポジティブ共有会を実施しました。これはチームメンバーのいいところをそれぞれNotionでチケットに書き出し褒め合うというものです。きっかけはチームメンバーから自分がどう思われているのか知りたいという要望からでした。3ヶ月のチーム開発をしている間に2回実施しました。スクラムではチームワークがとても重要です。スクラムは全員が自律的に動くことが大切であり、バラバラに動いていては完成するプロダクトもいいものが作れなくなってしまいます。褒め合う時間は少し恥ずかしい面もありましたが、チームメンバーの相互理解の向上や自分がどこで期待されているのかなどを知ることができ、チームの一員としての帰属意識が強くなりました。 結果と感想 新卒研修ではスクラムを用いて5スプリント目まで回すことができました。1スプリント目で開発したものと5スプリント目で開発したものではクオリティが全く違い、プロダクトを成長させていくという経験も積むことができました。Safieというプロダクトを作っていく会社でエンジニアをしていく上で今後自分たちのプロダクトがどんなものになっていくのかを意識しながら開発しなければ世の中の課題を解決できないプロダクトになってしまいます。プロダクトが成長し続けることが重要というよりはプロダクトを運用していく上でどう成長させていくのか見失わないことが重要だと感じました。 この記事を読んで入社した時のイメージがついていただければ幸いです。他の記事では私たちの作ったisai connectについてなども書かれていますのでぜひご覧ください。
アバター
この記事は Safie Engineers' Blog! Advent Calendar 1日目の記事です 導入 はじめまして!2024年に入社し、現在は第4開発部 コアデバイスグループに所属しております山口と申します。 今回は、2024年新卒エンジニア研修の紹介をしたいと思います。 導入 新卒研修の軽い紹介 チーム紹介  開発体制について タスク管理について コーディング規則 チーム開発前にやったこと まとめ 新卒研修の軽い紹介 セーフィーの新卒研修ではチーム開発をおこなっています。チーム開発を通してチームマネジメント・開発(フロント、サーバ、デバイス、CI・CD)・運用・保守を学んでいくのが目的になります。 チーム開発では、2024年度の新卒エンジニアは7名で「社内の負」を解決するシステムについて、アイデアを出し合って開発しました。新卒エンジニアメンバーで話し合った結果、社内で用意されている「異才ランチ」という福利厚生制度に着目し、これを活性化しようという話になりました。 異才ランチを効率化するシステムについては他のテックブログで紹介があると思いますので、本記事では頭出し程度にしておきます。 また、新卒研修のトレーナーには去年の新卒の方々が担当してくださっています。 新卒エンジニアメンバーが執筆した記事については以下リンクをご参照ください! 新卒研修の紹介とチーム開発前にやったこと ←本記事 2024年新卒エンジニア研修-アジャイル開発編 2024年新卒エンジニア研修-isai connectについて 2024年新卒エンジニア研修-isai connect開発のアウトプット_サーバーサイド 2024年新卒エンジニア研修-フロントエンド開発編 2024年新卒エンジニア研修-インフラ構築編 2024年新卒エンジニア研修-isai connect開発のアウトプット_デバイス編 2024年新卒エンジニア研修-新卒研修の成果発表とその後 チーム紹介  新卒研修を始めるにあたってチーム名とロゴを作成しました。 今後会社で24卒エンジニアと認識されるより、チームとして認識してほしいこと、チームとして一体感をだしたいなどが理由です。 チーム名には悩みましたが、各メンバーの頭文字をとって SSSTIFY(トリスティフィー) と命名しました。 ロゴは新卒デザイナーに作成してもらいました。こちらも何度かやり取りを繰り返し、最終的に以下のようなデザインになりました。 このロゴは開発したプロダクトでも使用しています。 開発体制について チーム開発でプロダクトをリードするプロダクトリーダーと技術まわりについてリードするテックリードといった役割もチームで選出しました。 出社する頻度もチーム内で決め様々な働き方を試してみて、自分にはどの働き方があっているかなども考えました。 リモートワークでのコミュニケーション方法について考え、我々は「Gather」を使用してみました。リモートワークの際、Gatherではマップ上で話しかけたい人の近くに移動すれば会話ができるので、現実でちょっと話を聞きに行くみたいな感覚に近いものがあって気軽に相談もできたのが良かったと思います。 下記の画像は実際に開発中に使用したGatherの画像になります。 利用ルールは下記のように定めていました。 利用ルール 利用する曜日:月・水・木 リモート可能な日に利用 リモート: 月 出社: 火・金 自由: 水・木 ログイン時間:出勤時~退勤時まで 利用範囲はSSSTIFYの7名とする 他者の招待は原則NG トレーナーさんなど参加が必要な場合は相談 カメラは常にON マイクは基本OFF、話しかける際にON 雑音などを拾う可能性があるため 全体のミーティングはGoogle Meetを利用 個人間の話し合いではGather上で画面共有など利用可 チャットはSlackを利用し、Gatherでは使わない 履歴を残しておくため 我々のチーム開発ではアジャイル開発を取り入れ、スプリントごとに各領域の開発をできるようにもしました。 例えば、今スプリントでフロント開発していた人が次回スプリントではデバイスの開発をしているといった感じです。 下記のように開発に向けたチームの目標を決めていました。 チームでやりたいこと(目標) 型にはめたスクラムを経験してみる レビューを定期的に受ける(進捗定例) スプリントを2周以上回す経験をする 使ってもらえるプロダクトにする 満足度などの定量指標を設ける 自分が使いたいプロダクトを作る 全員が全ての技術に触れる 1スプリントで二つ以上の技術を触れることが目標 いっぱいタスクを消化している人にどんなタスクあるか相談するのもあり チケットは基本メインの技術スタックをとっても良いが、他の分野についてはレビューで寄与する レビューでは動いたからOKといったものではなく、積極的に実装者やその他の関係者に質問するなど理解を深めるよう意識する タスク管理について タスク管理には「Backlog」を使用しました。 チーム開発ではgitのbranch名をBacklogの課題IDと紐づけることでgithub上でプルリクがマージされたらBacklog上でのチケットも完了ステータスに移行するようにし、なるべく繰り返し作業を減らすことを意識して開発に集中しやすい環境を目指しました。 githubのプルリクとBacklogのチケットが紐づいていることで、どのチケットに対するプルリクなのかも一目で判断でき履歴を追いやすいのも良かったです。 コーディング規則 こちらはプルリクでチェックすべきコーディング規則の内容になります。プルリクの内容がどの領域に対する変更なのかでプルリクのテンプレートが決まります。 テンプレに記載されている項目を担当者は確認し、確認ができし次第レビューを各メンバーへお願いするといった流れでレビューしていました。 また、各フォルダごとにCodeOwnerを選定し、各領域で必ずレビューをもらうべき人を決めていました。変更に対して責任を持ってレビューをするといった意味合いも含んでいます。 チーム開発前にやったこと チーム開発がはじまるまでは初めに「Udemy」という動画教材を取り扱っているサイトを用いてプログラミングの基礎について学習をしていました。 私たちはセーフィーの新卒二期生ですが、一期生の方々の研修フィードバックを元に厳選した動画を中心に学習を進めていました。 既に基礎を理解している人は自由に興味のある領域の動画で学習していました。動画教材のリストとしては、セーフィーのプロダクトに関係のあるものが主に選定されています。 Githubを学んだことがない人はUdemyの動画から学んでいましたが、それだけでは理解は浅かったので、チームで集まって実際にコマンドを叩きながら理解を深めていました。やはり実際に手を動かして学ぶのが一番です。 まとめ 本記事を読んで、少しでも入社したときのイメージがついていただけたら幸いです。 研修終了後、別々の部署に配属された事でSSSTIFYのメンバーとの直接的な接点は減りましたが、他部署のシステムや技術について気軽に相談できる関係性が構築できて今も仲良くさせてもらっています。 また、セーフィーでは新卒採用が始まってから2年が経過していますが、実際に研修を経験した方々のフィードバックから研修内容を柔軟に変えて、最良の研修を模索している段階にあります。 来年度入社される新卒エンジニアの方々のためにも、今回の研修についてしっかりフィードバックを行いました。 今後もさらに研修内容をブラッシュアップしていき、来年度の新卒エンジニアの方々が楽しいと思える研修にできると嬉しいです。
アバター
概要 こんにちは!2024年新卒エンジニアの古谷です。今回は技育祭 2024【秋】にエンジニアリングオフィスの副部長の武田さんと登壇してきたことについてお話ししようと思います。 概要 技育祭とは 登壇目的 登壇概要 所感 技育祭とは 技育祭は「技術者を育てる」ことを目的としたエンジニアを目指す学生のための日本最大のオンラインカンファレンスです。各企業の経営者やCTO、エンジニアが二日間に渡って多くの学びや気づきを提供するために登壇します。 登壇目的 私の登壇には2つの目的がありました。 2024年新卒エンジニア研修で身につけた「プロダクト開発で大切なこと」を学生の皆さんに共有し、より引っ張りだこなエンジニアになってもらうこと 私が学生時代にウェブアプリを開発していた時には得られなかった知見をたくさん紹介しました。ハッカソンなどの開発では得られにくい、運用を大前提とした開発における大切なことに、興味を持っていただけると考えました 学生の皆さんにセーフィーがどんなことをしているのか知り興味を持っていただくこと 当日は120人を超える方々に見にきていただき、コメントの反応も良好でした。登壇直後にはカジュアル面談の申し込みが来るなど、学生の皆さんに興味を持ってもらうことができました 登壇概要 以下は登壇した時の資料です。 speakerdeck.com スライドの中では、プロダクトとプロジェクトの違いを説明しつつ、プロダクト開発で大切なことを2024新卒エンジニア研修で作った「isai connect」という異才ランチを活発化させるためのプロダクトを例に説明しています。異才ランチはセーフィーの福利厚生の一つで、他部署の方とランチに行くとランチの費用を会社が負担してくれる制度です。 後半は、私と武田さんによるセッションと学生の方々からの質疑応答を行いました。質問には以下のようなものがありました。 なぜセーフィーに入社したのか プロダクトのアイデアを思いつく良い方法 キャリアビジョンとしてプロジェクトマネージャーを経てプロダクトマネージャーを目指すことはあるか マネージャー職でも積極的にコーディングできるか 就職活動時の最終候補企業 所感 新卒で技育祭に登壇することは大変緊張しましたが、学生時代にお世話になった技育祭に社会人になってからも関わることができ嬉しかったです。 セーフィーでは、様々な挑戦ができる環境があります。この記事を読んでもし興味を持っていただけた方は、ぜひ採用ページもご覧ください。カジュアル面談のみでも大歓迎ですので、お気軽にご連絡ください。 safie.co.jp
アバター
こんにちは、第3開発部AI Visionグループのおにきです。 この記事では11月16日(土)にセーフィー社内の会議室で行われたイベント、「 第62回 コンピュータビジョン勉強会@関東 ECCV2024読み会 」について紹介したいと思います。 コンピュータビジョン勉強会@関東 開催にいたる経緯 準備 会場の確認と設備チェック 参加者への配慮 懇親会の準備 当日の様子 参加者の到着 セーフィーの紹介 セーフィーからの発表 その他の発表と全体の印象 懇親会 さいごに コンピュータビジョン勉強会@関東 「 コンピュータビジョン勉強会@関東 」は、takminさんを中心とするメンバーによって14年前から運営されている勉強会です。今回で62回目を迎え、コンピュータビジョン分野では長年にわたり継続している老舗の勉強会として知られています。研究・開発をしているリサーチャー、プロダクトの開発をしているエンジニア、大学で研究を行っている学生など、コンピュータビジョンに関わる多様な方が参加者として集まるレベルの高い勉強会です。 これまで様々なテーマで勉強会は開催されてきましたが、CVPR、ECCV、ICCVと言ったコンピュータビジョンの領域でのトップカンファレンスで発表された論文を解読して紹介するという形式の勉強会は参加者も多く盛り上がるテーマの一つでカンファレンスと時期を合わせて開催されてきました。今回はミラノで行われたECCV(The European Conference on Computer Vision)2024が対象の勉強会となりました。 開催にいたる経緯 私自身もコンピュータビジョンのエンジニアとして、10年以上前から何度かこの勉強会に参加してきました。その中で2回ほど発表の機会もいただき、大変お世話になっています。 夏の勉強会に参加した際、主催者の方々と話をする機会がありました。その中で、セーフィーが1年前にオフィス移転をし、100名収容可能な会議室があるので会場提供できるかもという話になりました。 ちょうどその頃「Mobile Dev Japan #3」という勉強会がセーフィー内で開催されていました。これにより、セーフィー社内でもIT系の勉強会の開催に対して前向きな雰囲気が高まりつつありました。 8月頃にECCV読み会の日程調整と参加者募集が始まったので、会場提供できると連絡したところぜひという回答をいただいたのでセーフィーで開催をすることが決まりました。 せっかく自社のオフィスで開催するということで、AI Visionグループから2名のメンバーを登壇させてもらいました。 準備 会場の確認と設備チェック 今回は土曜日の開催ということもあり、そもそも土曜日はビルのエントランスドアが空いているのかなど入館の仕方についての確認を行いました。 会場となる会議室の設備については、私自身が設定したことがなかったため、前日の金曜日夕方にチェックを行いました。平日開催であれば社内にいる人に助けてもらえそうですが、週末となると他の社員は誰もいないので、入念にチェックは行いました。 参加者への配慮 ECCV読み会は休憩を挟みつつ、午後1時~6時半までの長時間で開催されます。トップカンファレンスの論文の内容を紹介するため、参加者も脳をフル稼働します。セーフィーの入っているオフィスビルは週末になるとコンビニが営業しておらず周囲にもコンビニがないため、せめて飲み物とお菓子を提供しようということで水・お茶とブラックサンダーを用意しました。 お茶と水(ブラックサンダーは休憩時間に提供しました) 弊社製品を触っていただけるデモとグッズとパンフレットも用意しました 初めてセーフィーのオフィスに訪問する方ばかりなので迷わないように案内も設置しました。 懇親会の準備 コンピュータビジョン勉強会@関東では毎回勉強会後に懇親会が開かれ、そちらも盛り上がります。今回はセーフィーからスポンサーとしてお酒と食べ物を提供することにしました。みなさんどれくらいお酒を飲むのかの予測はなかなか難しいですが、適当に一人あたりの本数を決めて発注しました。 当日の様子 参加者の到着 開催時間の30分前から会場に入れるように案内を開始しました。当初は90人近くイベント登録していただいていましたが、実際に入った数は50名弱でした。このあたりのキャンセル者の多さはどの勉強会でも共通の悩みのようです。それでも、50名もの方が実際にセーフィーに来ていただいたということは嬉しい限りです。 セーフィーの紹介 takminさんの挨拶の後に、私から会場提供企業としてセーフィーの会社紹介を行いました。50人近いコンピュータビジョンエンジニアの前でセーフィーを紹介し、実際にプロダクトのデモを見てもらうことでセーフィーという会社とセーフィーでのコンピュータビジョンエンジニアの仕事を認識してもらえたかと思います。発表後にXで確認すると参加者からの反応も良かったようです。 セーフィーからの発表 セーフィーからは周さんと橋本さんに登壇してもらいました。 周さんの発表 Li et al., ”VideoMamba: State Space Model for Efficient Video Understanding” Video Understandingタスクのために最新のアーキテクチャであるMambaを応用した論文です。Deep Learning、Transformerに次ぐ新しいアーキテクチャとしてのMambaを説明した後に、Video Understandingタスクに応用するという内容で数理的にかなり複雑なものでしたが、最新のアーキテクチャということもあり参加者の興味は高かったようです。 speakerdeck.com 橋本さんの発表 Ciortan et al. , “Minimalist Vision with Freeform Pixels” CNNの畳み込み演算を光学系で行うことで、計算機での演算を軽量化するという論文です。ECCV2024のBest Paperを受賞した論文で、発想が非常にわかりやすい研究という印象でした。橋本さんは実際に学習をしてみたそうですが上手くいかなかったようですが、実際に手法を試してみるというのは大切な姿勢だと再認識しました。 speakerdeck.com その他の発表と全体の印象 セーフィーからの2名を含め、合計11名の方が論文の紹介を行いました。どの資料もわかりやすく、また質疑も発表者の方への敬意があるやり取りになっており、本当に良い勉強会コミュニティーであると感じました。 コンピュータビジョンと言ってもその扱う領域が幅広いことと、いろいろな発想のもとに研究が行われているということを知ることができ、非常によい刺激を受けることのできる勉強会でした。 懇親会 勉強会後、ネットワーキングを目的とした懇親会を開催しました。参加者は飲食を楽しみながら、それぞれの会社での業務の進め方やコンピュータビジョン分野での業務上の課題など、普段社内で業務を知ることのできない内容について情報交換をすることができました。このように社外の方と交流することで普段考えている課題などを共有したり、他社での状況を知ることができます。それらは日々の業務のヒントにつながっていくと思われるので、今後も積極的に行っていきたいと考えています。 さいごに 今回の勉強会は週末開催で参加者も多く準備が大変でしたが、チーム内外のメンバーの協力のおかげで開催することができました。開催前は不安なことも多々ありましたが、大きな問題もなく無事開催することができました。スタッフとして参加したセーフィーのメンバーからも楽しかったし勉強にもなったという声を聞いており、開催して本当に良かったと感じています。 セーフィーでは今後もコンピュータビジョンを用いた画像認識AIの開発を進めて行くので、一緒に開発を行うメンバーを募集しています。 open.talentio.com
アバター
概要 AIチャットツール導入の目的 LLMおよびAIチャットツールの選定 機密情報・個人情報とLLM LLMの比較表 AIチャットツールの比較表 Bedrock Claude Chat AIチャットボットの導入 Slack連携機能 まとめ 概要 近年大規模言語モデル (LLM) 技術の発達に伴い、社内でもGitHub Copilotをはじめとする各種AIツールの導入が進んでいます。 本件ではLLM技術を用いたAIチャットツールとしてAmazon Bedrockおよび Bedrock Claude Chat を導入した経緯について紹介します。 AIチャットツール導入の目的 2022年末にOpenAI社よりChatGPT 3.5がリリースされて以降LLM技術およびAIチャットボットが急速に普及し、様々な分野で活用されるようになりました。 弊社でもGitHub Copilotによるコード生成補助などでAI技術の導入による社内業務効率化が進められており、また生成AIと映像を組み合わせた新たなサービスの創出が進んでいます。 一方でAIチャットサービスについては社内機密情報・個人情報を扱わない範囲で個別に使用することが認められているだけで、本格的な社内業務改善に用いるのには難しい状況でした。 そこで、社内業務効率化のため、あるいはより高度なAIツール導入の足がかりとするため、また生成AIを用いたサービス創出のための経験値を積むために社内AIチャットボットを導入することにしました。 LLMおよびAIチャットツールの選定 LLMおよびAIチャットツールを選定するにあたり下記の点を考慮しました。 LLMの提供においてはサービスプロバイダが入力を再学習のために使用したり不正使用レビューのため閲覧することが多いため、機密情報・個人情報の扱いについては通常のSaaSサービスと比べ追加の検討が必要になります。 LLM性能 同世代のLLMと比較して十分な性能を持つこと AIチャット機能 ユーザーごとのチャット履歴の保存ができること 検索拡張生成 (RAG) による社内ナレッジに基づくAIチャットボットの提供 その他高度な機能 (Agent、外部ツールアクセス等) 管理機能 SSO ユーザーごとの費用の確認 コンプライアンス LLMの入力が再学習に使用されないかオプトアウトが可能であること LLMの入力が人間のレビューに使用されないかオプトアウトが可能であること 費用 安価であること 機密情報・個人情報とLLM SaaSとしてLLMまたはAIチャットサービスを使用する場合、個人情報を入力することは第三者提供にあたり、ユーザー本人の同意が必要になります。 一般にGMail, Google Drive等クラウドサービスで個人情報を扱うには、対象サービスがいわゆるクラウド例外 ( 個人情報の保護に関する法律についてのガイドライン Q7-53 等) に該当する必要があります。 LLMへの入力が再学習など出力の生成以外の用途に用いられる場合、クラウド例外に該当しません。( https://www.ppc.go.jp/news/careful_information/230602_AI_utilize_alert/ ) またLLMへの入力が不正検知などのために人間によるレビューが行われる場合、クラウド例外に該当しなくなるという見解があります。 【AI】生成AIとクラウド例外 本件では再学習および人間によるレビューが行われないことを条件に、機密情報 (社内秘情報・機密保持契約にカバーされるものを除く) および個人情報の扱いが可能な社内AIチャットボットの導入を進めました。 LLMの比較表 名称 Chatbot Arena Score 再学習 レビュー OpenAI ChatGPT GPT-4o-2024-08-06 1264 有り (オプトアウト可) 人力レビュー (オプトアウト申請可) OpenAI ChatGPT API ChatGPT-4o-latest 1338 無し (オプトイン) 人力レビュー (オプトアウト申請可) Anthropic Claude Claude 3.5 Sonnet 1268 有り (オプトアウト可) 人力レビュー (オプトアウト申請可) Anthropic Claude API Claude 3.5 Sonnet 1268 有り (オプトアウト可) 人力レビュー (オプトアウト申請可) Google Gemini Gemini-1.5-Pro-002 1304 有り 人力レビュー Azure OpenAI GPT-4o-2024-08-06 1264 無し 人力レビュー (オプトアウト申請可) Amazon Bedrock Claude 3.5 Sonnet 1268 無し 自動レビュー ※ Chatbot Arena Leaderboard (2024-10-14) より ※ 不正検知レビューのオプトアウトは申請が受諾される必要があります AIチャットツールの比較表 提供方法 対応モデル SSO カスタムプロンプト RAG Reasoning 外部ツール コンテンツ編集 費用 OpenAI ChatGPT SaaS ChatGPT ChatGPT Enterprise (SAML) GPTs GPTs o1-mini Bing, DALL-E, Code Interpreter, Retrieval, Custom Actions Canvas >= $30/user/month (Enterprise) Anthropic Claude SaaS Claude Claude Enterprise Projects Projects - - Artifacts >= $30/user/month (Enterprise) Google AI Studio SaaS Gemini Google Workspace - - - - - 従量課金 Bedrock Claude Chat セルフホスト (UI) + SaaS (LLM) Bedrock (Claude等) Amazon Cognito (SAML/OIDC) BOT BOT ReAct DuckDuckGo - インフラ料金 + API従量課金 Bedrock Claude Chat Bedrock Claude Chat はAmazonによって開発されているチャットボットUIで、Amazon Bedrock基盤モデルによりAnthropic Claude等を利用可能です。ユーザーはCDKを使用して自身のAWS環境にソフトウェアをデプロイすることができます。 Bedrock Claude Chatは必要な条件を満たし、費用がSaaS製品と比べ非常に安価であるためこれを導入しました。 LLM: Anthropic Claude 3.5 Sonnetが使用でき、選定当時での最高性能 AIチャット: ユーザーごとのチャット履歴の保存、RAG等必要な機能が使用可能 SSO: Amazon CognitoによるSSOが使用可能 コンプライアンス: 再学習および人間によるレビューが行われない 費用: 比較的安価なLLM APIが使用でき、インフラ費用が非常に安価 (月額数百ドル程度) Bedrock Claude Chat 画面イメージ AIチャットボットの導入 Bedrock Claude Chatをデプロイし、全社利用を開始しました。 ユーザーはSSOでアプリにログインし、一般的なAIチャットボットとして使用することができます。 またユーザー権限でボットを作成することができ、カスタムプロンプトの設定や外部URLまたはドキュメントを知識ソースとしてRAG機能を構成し、共有することができます。 現在セーフィー製品の仕様のQ&Aボットなどいくつかの公開ボットが稼働しています。 Slack連携機能 Bedrock Claude ChatにはAPI公開機能があり、こちらを利用してSlackとの連携機能を開発しました。 suzuki-safie/slack-chatbot-fn SlackのCustom FunctionとしてBedrock Claude ChatのBotの公開APIを呼ぶことで、Slack上からチャットボットの機能を利用することができます。 まとめ 社内AIチャットボットとしてBedrock Claude Chatを全社導入し、社内業務改善に使用可能なツールを安価に導入することに成功しました。この導入により、AIを活用した業務効率化の基盤が整いました。 今後は以下の取り組みを通じて、AIチャットボットの活用をさらに推進していく予定です: 利用方法の周知と活用促進 RAG(検索拡張生成)などの高度な機能の使用方法について、社内トレーニングや事例共有を実施 ユーザーの利用体験を向上させ、AIチャットボットの日常的な活用を促進 開発用途での利用拡大 GitHubのコードリポジトリをソースとしたRAGの構築 生成AIを用いた新サービスの創出 AIチャットボット以外の用途でのBedrock基盤モデルの活用 社内アプリケーションやサービスへのAI機能の組み込み これらの取り組みを通じて、AIテクノロジーの社内での浸透を図り、業務効率の向上だけでなく、新たなサービスの創出にもつなげていきます。
アバター
はじめに セーフィー株式会社 の AI Vision グループでテックリードを務めます橋本貴博です。 私たちのチームでは、レビューの属人化や特定のメンバーへの負担の集中が課題となっていました。どのメンバーがレビューするかによって、そのやり方やフィードバックの質にバラつきが出ることも少なくなく、これがコードの品質に影響を及ぼしていました。 そのため、チーム全体でレビューを行うことで、コードの知識を全員で共有し、レビューのやり方や品質を標準化したいと考えていました。こうすることで、誰がレビューしても同じように高品質なコードが保たれるようになります。 さらに、Pull Request (PR) の数をKPIとして考え、それに基づいて実装を推進することも重要視しました。PRの数を定量的な指標にすることで、チームの成果を把握し、開発の効率化を図りたいと考えました。 そこで、GitHubのPRを解析して可視化するツールを開発し、オープンソースで公開することにしました。このツールを使うことで、PRの状況を簡単に把握できるだけでなく、レビューの分散や効率化にもつながると考えています。 本記事では、開発したツールの機能と活用、利用している GitHub REST API、ツールの使い方について示します。 はじめに 機能 積み上げ縦棒グラフ ヒートマップ ネットワークグラフ サンキーダイアグラム GitHub REST API Search API Reviews API Review Requests API 使い方 ソースコード むすび 機能 特定の期間において、指定されたメンバーが author、reviewer、もしくは requested review されているPRの数を集計します。結果を可視化して png 画像として出力します。出力される図は以下の通りです。 積み上げ縦棒グラフ ヒートマップ ネットワークグラフ ノードの大きさ: PR作成数とレビューした数の合計 エッジの太さ: レビューした数と、レビューされた数の合計 サンキーダイアグラム 以下では、2024年9月の1か月のPRを集計した結果を例として説明をします。 積み上げ縦棒グラフ Author はPRを作成した数です。極端にPR数が少ない場合、実装に時間がかかっていたり、実装以外の業務の割合が多くなっているといった理由が考えられるので注意しています。 Review-requested は現時点でレビュー依頼されている数です。レビュー依頼が特定のメンバーに溜まっている場合は再割り当てが必要な可能性があるので注意しています。 Review-completed は、レビューが完了している数です。PRに対して1回以上のレビュー(comment, approve, request changes)を行った数から、完了していない場合を除くため、現時点でレビュー依頼されている数を除いています。私たちのチームでは特定のメンバーにレビューが片寄ることを防ぐため、可能であればレビュー数が少ないメンバーにレビュー依頼を行うことを推奨しています。 ヒートマップ 積み上げ縦棒グラフは、各メンバーがレビューした総数は分かりますが、レビュー依頼元の内訳を読み取ることはできません。そこで、依頼元と依頼先の関係を可視化するためにヒートマップを出力するようにしました。ヒートマップの縦軸は依頼元、横軸は依頼先を示しています。PR作成者によっては、依頼先が偏りレビュー属人化の傾向があることが読み取れると思います。 ネットワークグラフ ネットワークグラフは、ヒートマップの情報をさらに直感的に分かりやすく可視化することができます。ノードの大きさは各メンバーのPR作成数とレビュー数の合計から、エッジの太さは2人のメンバーの間でレビューした数とレビューされた数の合計から決定しています。 ノードの位置は Spectral Layout を用いています。これにより結びつきが強いノードは近くに配置されます。したがって、コードやレビューの知識共有が近接するメンバーで密に行われており、逆に離れたメンバにはあまり共有が行われていないのではないかと仮説を立てることができます。 サンキーダイアグラム サンキーダイアグラムは、ある量とその流れを可視化します。ここでは、レビュー依頼の量とその流れを見ることができます。下図において、左端の列はレビューの依頼元と依頼の量を、右端の列はレビューの依頼先と依頼された量を示しています。依頼元から依頼先への流れがグレーの帯で示されています。サンキーダイアグラムを用いると、直感的に誰から誰へどれくらいの量が分配されたのか把握できると思います。 GitHub REST API ここでは、GitHub REST API を用いたPR情報の取得方法について説明します。このツールでは3種類のAPIを利用しています。 まず、 REST API for search (Search API) を用いて集計に含めるPRのリストを取得しています。次に、個々のPRについて、 REST API endpoints for pull request reviews (Reviews API)と、 REST API endpoints for review requests (Review Requests API)を用いて、レビューのステータスとレビュー依頼のステータスを取得しています。 集計の高速化のため、過去に取得した時点から更新が無いリポジトリについてはキャッシュを利用しています。 Search API Search API は、 github.com/search と同様のクエリを用いてGitHub 内のオブジェクトを検索することができます。例えば、特定の期間、特定の組織で、特定のメンバが作成したPRを検索するには検索窓に以下のクエリを入力できます。 type:pr org:Safie author:member-a author:member-b author:member-c created:2024-09-01..2024-09-30 上記に対応して、REST API のURLは次のようになります。 https://api.github.com/search/issues?q=type:pr+org:Safie+author:member-a+author:member-b+author:member-c+created:2024-09-01..2024-09-30&sort=created&order=desc&per_page=100 Reviews API レビューしたメンバーを確認するのに Reviews API を用います。リポジトリのオーナーを {owner} 、リポジトリの名前を {repo} 、PRの番号を {pull_number} として、URLは以下になります。 https://api.github.com/repos/{owner}/{repo}/pulls/{pull_number}/reviews Review Requests API 現時点でレビュー依頼されているメンバーを確認するのに、Review Requests API を用います。Reviews APIと同様に、リポジトリのオーナーを {owner} 、リポジトリの名前を {repo} 、PRの番号を {pull_number} として、URLは以下になります。 https://api.github.com/repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers 使い方 config.py に GitHub token と集計したいメンバーのアカウント名を記載します。 github_token = "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" authors = [ "member-a" , "member-b" , "member-c" , ] 以下のコマンドを実行します。 python analyze.py # 直近1か月の集計 python analyze.py --from_date 2024 -09- 01 --to_date 2024 -09- 30 # 期間の指定 詳細な使い方は、リポジトリの README.md をご覧ください。 ソースコード こちら でソースコードを公開しています。ぜひ使ってみてください。 github.com むすび GitHub REST API を使ってPRを集計し、PRの属人化やチームの生産性の分析に利用する方法を紹介しました。もし同じような課題に直面しているチームがいれば、ぜひこのツールを活用してみてください。 セーフィーでは、新卒・中途を問わず、さまざまな職種の仲間を積極的に募集しています。詳細は セーフィー採用サイト をご覧ください。
アバター
こんにちは!Safie第2開発部のAndroidエンジニアのジェローム( @yujiro45 )です。 Androidで3D/ARモデルを表示するのは難しそうに見え、技術的に大変そうですね。 この記事では、 Sceneview-android を使用して簡単に3DとARモデルを表示する方法を紹介します。 SceneViewとは 導入 実装 アニメーション ARで動画を表示する まとめ SceneViewとは SceneView は Google Filament と ARCore を使用して3Dモデルを表示するライブラリです。 Thomas Gorisse (トーマス・ゴリス)と彼のチームによって開発されました。 Google Filament :Googleが開発している物理ベースのリアルタイムレンダリングエンジンです。 ARCore :Googleが開発したAndroid端末向けのARフレームワークです。 SceneViewは、以前のライブラリである Sceneform のKotlinバージョンであり、完全にKotlinで書き直されています。Sceneformはもはやメンテナンスされていません。 技術的には、SceneViewは3Dスペースで、カメラは中央に位置しており、座標はx=0、y=0、z=1です。 該当部分のコード 導入 この記事では、KotlinとJetpack Composeを利用する導入方法について説明します。ただし、SceneViewはAndroidのxml layoutや Flutter や React Native でも利用可能です。 SceneViewは2つのビューを提供します。 ARSceneView : Google FilamentとARCoreの両方を使用して、3DおよびARを表示する目的で利用されます。 SceneView : Google Filamentを使用して3Dモデルを表示するために利用されます。 SceneViewを追加するには、必要に応じてGradleファイルに適切な依存関係を追加するだけです。 ARSceneView dependencies { implementation( "io.github.sceneview:arsceneview:X.X.X" ) } SceneView dependencies { implementation( "io.github.sceneview:sceneview:X.X.X" ) } 💡 GradleファイルにARSceneViewの依存関係を追加すると、ARSceneViewとSceneViewの両方を使用できます。ただし、SceneViewの依存関係のみを追加した場合は、SceneViewのみを使用できます。 実装 SceneViewは現在、GLTFおよびGLBファイルをサポートしています。3Dモデルのファイルをres/rawフォルダに入れてください。3Dモデルを表示するには、 ModelNode を使用する必要があります。これにより、3Dモデルから3Dノードを作成することができます。 *glbとgltfファイルは以下のサイトで無料でダウンロード出来ます。 https://www.cgtrader.com/ https://polyhaven.com/ https://sketchfab.com/tags/glb 3Dファイルを追加したら、以下のコードを使用して表示できます。 ARSceneView SceneviewexampleTheme { val engine = rememberEngine() val modelLoader = rememberModelLoader(engine) // 3Dモデルの読み込み val modelNode = ModelNode( modelInstance = modelLoader.createModelInstance(R.raw.android) ).apply { // 3Dモデルの初期設定 scale = Scale( 1 / 40f ) position = Position( 0f ) } ARScene( modifier = Modifier.fillMaxSize(), engine = engine, modelLoader = modelLoader, childNodes = rememberNodes { // モデルノードの追加 add(modelNode) } ) } SceneView SceneviewexampleTheme { val engine = rememberEngine() val modelLoader = rememberModelLoader(engine) // 3Dモデルの読み込み val modelNode = ModelNode( modelInstance = modelLoader.createModelInstance(R.raw.android) ).apply { // 3Dモデルの初期設定 scale = Scale( 1 / 40f ) position = Position( 0f ) } Scene( modifier = Modifier.fillMaxSize(), engine = engine, modelLoader = modelLoader, childNodes = rememberNodes { // モデルノードの追加 add(modelNode) } ) } ビルドが通ったら、3Dモデルが表示されました! 🎉 ARSceneView SceneView 出典:Sketchfab, https://sketchfab.com/3d-models/android-7c30eda007684abbb78ea4b99d22fc2c  (2024/10/07アクセス) SceneViewにノードを追加するとき、 ドキュメント によれば、ノードのデフォルトの位置は (x=0.0f, y=0.0f, z=0.0f) で、軸は下の画像のようになります。 カメラを別の位置に移動したい場合は、以下のように指定します。 SceneviewexampleTheme { //... Scene( //... cameraNode = rememberCameraNode(engine).apply { position = Position(z= 5f ) } //... ) } アニメーション ModelNodeのtransform()というメソッドを使用して、位置や回転やScaleを変更することができます。 https://github.com/SceneView/sceneview-android/blob/1e303adf92f1f7b67eb9aa4f9fc731d75213ac97/sceneview/src/main/java/io/github/sceneview/node/Node.kt#L620-L633 fun transform( position : Position = this .position, quaternion : Quaternion = this .quaternion, scale : Scale = this .scale, smooth : Boolean = isSmoothTransformEnabled, smoothSpeed : Float = smoothTransformSpeed ) = transform(Transform(position, quaternion, scale), smooth, smoothSpeed) 前のコードでは、3Dモデルを表示する事が出来ましたので、モデルをタップしたときに180度回転させるようにしましょう。 ARSceneView SceneviewexampleTheme { val engine = rememberEngine() val modelLoader = rememberModelLoader(engine) // 3Dモデルの読み込み val modelNode = ModelNode( modelInstance = modelLoader.createModelInstance(R.raw.android) ).apply { // 3Dモデルの初期設定 scale = Scale( 1 / 40f ) position = Position( 0f ) } ARScene( modifier = Modifier.fillMaxSize(), engine = engine, modelLoader = modelLoader, childNodes = rememberNodes { // モデルノードの追加 add(modelNode) }, // タッチイベントのリスナー onGestureListener = rememberOnGestureListener( onSingleTapConfirmed = { _, node -> if (node == modelNode) { // モデルノードの回転 modelNode.transform( rotation = Rotation(z = 180f ), smooth = true ) } } ) ) } SceneView SceneviewexampleTheme { val engine = rememberEngine() val modelLoader = rememberModelLoader(engine) // 3Dモデルの読み込み val modelNode = ModelNode( modelInstance = modelLoader.createModelInstance(R.raw.android) ).apply { // 3Dモデルの初期設定 scale = Scale( 1 / 40f ) position = Position( 0f ) } Scene( modifier = Modifier.fillMaxSize(), engine = engine, modelLoader = modelLoader, childNodes = rememberNodes { // モデルノードの追加 add(modelNode) }, // タッチイベントのリスナー onGestureListener = rememberOnGestureListener( onSingleTapConfirmed = { _, node -> if (node == modelNode) { // モデルノードの回転 modelNode.transform( rotation = Rotation(z = 180f ), smooth = true ) } } ) ) } 結果を見てみましょう! ARSceneView SceneView ARで動画を表示する 3Dモデルの表示方法がわかったので、以下の動画をExoPlayer x Sceneviewで表示できるように実装していきましょう! こちら で無料動画を入手できます。 出典:Pexels, https://www.pexels.com/ja-jp/video/13299023/  (2024/10/07アクセス) Sceneviewのソースコードを見ると、 VideoNode が無効になっていることがわかりました。 また、Nodeのテクスチャを変更するには、Google Filamentの MaterialInstance を作成し、Sceneviewの MaterialLoader を使用して新しいテクスチャを適用する必要があります。そのためには、以下の手順を実行する必要があります。 こちらがコードです!✨ class ExoPlayerVideoMaterial( engine : Engine, exoPlayer : ExoPlayer, private val materialLoader: MaterialLoader, ) { // SurfaceTexture作成 private val surfaceTexture = SurfaceTexture( 0 ).apply { detachFromGLContext() } // SurfaceTexture→Surface作成 private val surface = Surface(surfaceTexture) // Textureのために、FilamentのStream作成 private val stream = Stream.Builder() .stream(surfaceTexture) .build(engine) // Texture作成 private val texture = VideoTexture.Builder() .stream(stream) .build(engine) // VideoTextureを使ったMaterialInstance作成 val videoInstance get() = materialLoader.createVideoInstance(videoTexture = texture).apply { setExternalTexture(texture) } init { // ExoPlayerのSurface設定 exoPlayer.setVideoSurface(surface) } } Sceneview側では、作成した ExoPlayerVideoMaterial を使いましょう! SceneviewexampleTheme { // ExoPlayerの設定... val player = ExoPlayer ... // さっきの作成したExoPlayerVideoMaterial val videoMaterial = ExoPlayerVideoMaterial(engine, player, materialLoader) val videoNode = PlaneNode( engine = engine, // 動画は16:9のため size = Size( 16f , 9f ), // NodeのMaterialInstance設定 materialInstance = videoMaterial.videoInstance, ) ARScene( //... childNodes = rememberNodes { // ノードの追加 add(videoNode) }, ) } 結果を見てみましょう! ARで動画を表示出来ました!😀 まとめ Sceneviewは、3DやARコンテンツを表示するための非常に便利なライブラリです。設定や使用がとても簡単です。しかし、私の個人的な経験から言うと、ドキュメントがあまり多くないため、もう少し複雑なことをしようとすると、Githubのソースコードを見る必要があります。アプリに3Dを追加したい場合は、ぜひ試してみてください! モバイルチームは開発する仲間を募集しています! open.talentio.com
アバター