「開発生産性の未来:世界と日本の最前線事例から培うFour Keys向上〜ハイブリッドカンファレンス〜」に参加してきました

お世話になっております。

株式会社Azoopでトラッカーズマネージャーおよびトラッカーズジョブの開発を担当している中山です。

先日、11月28日(水)にベルサール汐留で開催されたFindy様主催の「開発生産性の未来:世界と日本の最前線事例から培うFour Keys向上〜ハイブリッドカンファレンス〜」にオフラインで参加しました。

備忘録として、全体通しての感想と、いくつかのセッションについての感想をまとめていきます!

全体通しての感想

各セッションで以下のような話を聞く機会が多かったです。

  • Four Keysやプルリクエスト作成数などをモニタリングすることで、開発チーム内でそれらの数値の改善を促す事ができ、結果それらの数値は改善することが出来た
  • 開発チーム内の生産性をどのようにしてその先の開発生産性*1のモニタリングや改善に繋げていくか、模索中である

弊社はまず開発チーム内の生産性モニタリングから始める必要がありますが、実際にモニタリングを開始し、チームが良い状態に向かっているという事例を複数聞くことができ、開発生産性に取り組むモチベーションを高めることができました。また、取り組む過程で直面する可能性のあるいくつかの課題についても聞くことができ、大変有意義でした。

合同会社DMM.com様のセッション「1,000名のクリエイター組織 x 開発生産性」のまとめスライド

「日本における開発生産性の現在地」

ファインディ株式会社様のオープニングセッションになります。

セッションは、「開発生産性」というテーマが昨年より注目されていることについて触れる形で始まりました。

Findy Team+の導入チーム数が約12,000に達していると仰っていて、数字にこの分野への関心の高さが反映されていると思いました。

また、他のセッションでも度々話題になった生成AIの台頭が、開発生産性への注目に影響しているかなと個人的に感じました。

巷では「プログラマーは不要になる」との声も聞かれますが、それが言い過ぎであっても、開発チームの存在意義や活動を定量的な数字として、示すことができる状態になっている必要はあるなと感じます。

さらに、転職希望者が転職先を選ぶ際、「開発生産性への取り組み」を重視することが多いようです。

「開発生産性への取り組み」は個人だけでなく、チームや会社全体で取り組むべき課題です。モチベーションが高い人材を引き寄せるためにも、開発生産性への取り組みの実施、それを社外に発信することが重要だと感じました。

「開発生産性向上に向けた定量的なチーム目標設定のメリット」

株式会社モリサワ様とGO株式会社様のセッションになります。

モリサワ様の社内には、1日1人1プルリクエストを目標とするチームがあるそうで、すごいなと思いました。

プルリクエスト数を目標にすることで、プルリクエストに対する「ハック」が起きるのではという懸念の声に対しては、プルリクエストは課題ベースで作成するという前提に立った上で、「ハックはご自由に」「いくらでもプルリクエストは細かくしてください」「まずは数値を上げましょう」と伝えているそうです。

「まずは数値を上げましょう」というアプローチは、個人的にとても好きです。

自分たちに合った開発生産性を事前に定義することが可能な場合はそれに越したことはありませんが、多くのそうでない場合は、定義作成に多くの時間を費やすよりも、実際に数値を追いかけて見ることが良いと思っています。

そのプロセスの中で得られる知見をもとに、自分たちに合った開発生産性の定義を模索していく方が効果的だと思うからです。

チームの運営においても、アジャイルな価値観を取り入れたチーム作りを目指すべきだと、個人的には感じています。

定量的なチーム目標設定のメリットとしては

  • 目標を設定し、数値をモニタリングすることで、自律的な反省と改善を促す効果があった
  • 数値の設定がチーム全体に「行動しなければ」という意識を生み出した

と両社似たような見解を示していました。

アジャイルな価値観への変革〜大手開発組織によるDX推進〜」

株式会社セゾン情報システムズ様とKINTOテクノロジーズ株式会社様のセッションになります。

セッションの本筋ではありませんが、セゾン情報システムズ様が自社の営業部に開発部のファンを作るという話が印象的でした。

「あの開発部が作った製品だから、自信を持って販売できる」と営業部に思ってもらうことが狙いだそうです。

今回の登壇も、社外でのプレゼンスを高め、営業部にファンを作る取り組みの一環として行っているそうです。

社員に自社製品のファンになってもらうという話はよく聞きますが、営業部の方に開発部のファンになってもらうというのは自分になかった視点でした。

この視点を踏まえると、「開発チームが社外に発信していること」を社内に共有することの重要性を感じます。

おまけ

各企業様からのノベルティです。

ANKERの充電器は、Findy様のブースにあったガチャガチャで当たりました!

ありがとうございます🙇

最後に

弊社の開発チームは現在15名となりましたが、引き続き採用活動を行っています。

次のような方を随時募集しています!

  • Azoopの「開発生産性」向上に共に取り組んでくださる方
  • カンファレンスへの参加を通じて、そこで得た知見をチームメンバーと共有してくださる方
  • 開発チームの文化づくりが好きな方

選考プロセスへの進行なしでカジュアル面談を行うことも可能ですので、お気軽にお問い合わせください。

azoop.co.jp

トラッカーズオークションにおけるドメインリファクタリング

株式会社Azoopで「トラッカーズ」の開発している員(Yun)です。

最近、ドメインにおける大規模なリファクタリングを実施したので、その経緯と内容を共有したいと思います。

背景

「トラッカーズ」は、中古車のオークションサービスとしてスタートし、多くの試行錯誤を経てきました。私が入社する前から、さまざまなビジネスモデルが試されていたようです。主要なサービス「トラッカーズオークション」は、フリマやヤフオクのような形式から独自の形に進化してきました。しかしその過程で、サービスの変更が頻繁に行われ、コード上のドメインモデルが現実のビジネスモデルに追いついていない状態が発生しました。

リファクタリング前の状態

以下は、リファクタリングを始める前のドメインモデルの状態です。
主に二つバージョンのオークションが存在していました。

旧オークションモデル


 

現行オークションモデル

 
 そして、新しい概念として「入札会(Sale)」を導入し、以下のように車両をグルーピングしました。

全体像はこの感じです。
 

これらの複雑なモデルを扱うため、生のSQLを駆使していましたが、その結果、メンテナンスが困難なSQLが生成されることがありました。
(例えば、ログイン中に会社が自身の特定の入札会においての入札を全て抽出する)

新しいオークションモデル

現実のビジネスをべースに、議論を通して、重複の概念を除去した以下のような新しいドメインモデルを策定しました。
CurrentAuction/OldAuctionの責務をSaleとTruckSaleに移り、BidをTruckerSaleに紐づくように変更しました。

リファクタリングのステップ

新しいモデルへの移行をスムーズに行うため、以下の要件を満たす必要がありました。

  • サービスを停止せずに移行する
  • 業務に影響を与えない
  • 問題が発生した場合、すぐ前の状態に戻せる必要がある

これらの要件を基に、以下のステップでリファクタリングを行いました。

  1. 新しい関連を持つテーブルのマイグレーション
  2. 新旧のデータ構造を同時に生成
  3. 新しいデータ構造へのアクセスを優先し、新しいデータがない場合は古いデータにフォールバック
  4. 既存のデータを新しい構造に移行
  5. 古いデータを扱うコードの削除
  6. 不要な外部キーとテーブルの削除

結果として、オークションに関するドメインモデルが現実のビジネスモデルにより近づいたと感じています。

今後の展望

開発の効率は大幅に向上しましたが、まだ「トラッカーズマーケット」というサービスとの結合度が高い部分が残っています。次のステップとして、ドメインリファクタリングを続ける予定です。この挑戦に参加したい方は、是非、弊社のエンジニアチームにご応募ください

AWS WAF完全に理解した

いつもお世話になっております。Azoopの武田です。
ここ3ヶ月エオルゼアで毎週1回某お母様と戦い続けて欲しかった白魔道士の杖が取れました。

さて弊社のプロダクトである運送業務支援サービス『トラッカーズマネージャー』(以下、トラマネ)ですが、お客様である運送会社の車両やドライバーの情報といった大切なデータを預かり、また輸送案件の管理や請求書発行など基幹業務を担わせていただいています。
ブラウザ経由で使うという性質上インターネットという広大で物騒な世界に露出しており、ログ上でも既知の脆弱性を元にした攻撃や攻撃の足掛かりを探す不審なアクセスを観測しています。
弊社のプロダクトに攻撃を仕掛けてくる悪い人たちをレイドの時間切れを迎えた光の戦士たちと同じように

『渦なす生命の色、七つの扉開き、力の塔の天に至らん!』

と魔法一撃でワイプできたらいいのですが、この世界にはそんな都合のいいものはないのでトラマネではウェブアプリケーションファイアウォール(WAF)を導入して防御を固めています。

WAF

WAF(Web Application Firewall)とはHTTPリクエストのヘッダやボディの内容を監視し脆弱性を突いた攻撃を防ぐセキュリティ対策です。例えばウェブアプリケーションセキュリティの教科書の最初ほうに載っているような「フォームにスクリプトタグを仕込む」というような単純なXSSから世界中を震え上がらせた(?)Log4j脆弱性のような既知の脆弱性を使った攻撃を防いでくれます。
弊社ではプロダクトのインフラとしてAWSを使っており簡単に導入できることからAWS WAFを使用しています。

AWS WAF

WAF自体はF5やImpervaなどのセキュリティベンダーからEC2で動かすためのAMIがAWS Marketplaceを通してリリースされており、慣れていたりより詳細に設定したいといったニーズには対応できますが専門的な知識がないと構築も難しく私を含めWAFについてあまり詳しくないメンバーで運用するにはハードルが天に届く勢いで高いです。
一方、AWS WAFを使うとALB, CloudFront, API GatewayとAppSyncのいずれかを使ってさえいればマネージメントコンソールから操作するだけで導入できるためそれだけでなんとか地上から見えるぐらいまでハードルを下げることができます。さらに後述するスコープダウンステートメントを設定するときのクセの強さはあるものの簡単な操作でルールやログの保管などの設定を行うことができます。また導入するルール自体もAWSが無料のマネージドルールセットとしてメジャーなものを用意しているのでそれをひとまず入れるだけでも対策の導入としては十分でしょう。
またAWS以外のもセキュリティベンダー各社がAWS WAF向けにAWS Marketplaceでマネージドルールセットを時間+リクエスト数による課金で販売しているので比較的安価に専門ベンダーの知見を取り入れることが可能です。

構成と運用

ではここでトラマネにおける構成と運用についてみていきます。

AzoopのWAF構成

トラマネはALBでリクエストを受けて後ろにFargateで動作しているRails製のアプリケーションサーバがいるというシンプルな構成になっています。(データベースその他のコンポーネントは省略)
Web ACLはステージング(QA用)環境と本番環境で共有しており挙動を揃えることでステージング環境でWAFの挙動起因による不具合に早いタイミングで気付くことができるようにしています1

ルールセット

Web ACLに設定しているルールはAWSマネージドルールといくつかの独自ルールを組み合わせてセットしています。

一部を抜粋すると以下のとおりです。

AWSマネージドルールセットのうち最初の5つは様々なブログやサイトで「基本セット」として紹介されていることがあるものです。基本セットと紹介されるだけあってメジャーな攻撃は一通り網羅されています。これをIP評価ルールと組み合わせることで体感で半分以上の攻撃は防げています。
さらにトラマネは日本国内で利用されているお客様がほとんどのため一部の国を除き海外からのアクセスを遮断することで8割近い攻撃を防げるようになりました。ここで一部の国としたのは例えばアメリカを遮断するとGoogleのクローラーまで遮断してしまう & クローラーのみ通すとクローキングにあたり禁止行為に抵触する可能性があるためです。

クセが強いスコープダウンステートメント

AWS WAFは検査対象をスコープダウンステートメントで設定できます。
スコープダウンステートメントは「検査対象を決める条件」なので設定時はあるパスを除外したいときは「このパスは検査しない」ではなく「このパス以外は検査する」ように書く必要があります。1つだけならNOTの設定ができるので簡単にできますが複数のパスを除外したいときは少し面倒です。NOTは複数設定できないのでスコープダウンステートメントを設定するときにANDまたはORを追加しそれぞれのスロットの「Negate statement results」にチェックを入れることになります。

つまり、複数のNOTを書くにはド・モルガンの法則による変換が必要です……私は頭の中で組み立てるのが苦手なのでメモ用紙に書きながらやりました……!将来のアップデートでこのあたりをいい感じにできるようになることを期待したいと思います。

マネージドルールセットから一部を除外する

AWSが提供しているマネージドルールセットから一部のルールを除外したい場合もあるでしょう。ルールのアクションはその種類に関わらずラベルを付与するのでマネージドルールセットのアクションはCOUNTにして後続に付与されたラベルに対するアクションを決めるルールを追加します。独自ルールは数による課金もあるので細かくやりすぎると結構な出費になることがあるので必要最小限に抑えるようすると運用にもお財布にも優しいです。

WAFのログ

弊社ではログは基本的にDatadog Logsに集約しており、AWS WAFのログもS3を経由してDatadogに流すことで検索できるようにしてあります。Datadog LogsはデフォルトでAWS WAFが出力するログをパースできるようになっているのでとりあえず流せば簡単に検索できるようになります。
AWS WAFは何も設定しないとすべてのアクションのログが送信されてくるので膨大な量になり検索性やお財布を大変痛めつけることになります。そのためCOUNTとBLOCK, EXCLUDED_AS_COUNTのログのみ出力されるように設定しています。

お客様のアクセスに対して意図しないブロックが発生したときはDatadogを使ってログを検索しスコープダウンステートメントを追加するといった対策を実施できるようにしています。

まとめ

トラマネではAWS WAFやセキュリティ診断を活用してお客様の情報を守っています。誤検知が起きて意図せずお客様をブロックしてしまってもDatadog Logsを活用して素早く問題を発見し必要なアクションを取れるようにしています。

そしてタイトルで完全に理解したと言っていますがわからないことだらけなのでこれからもよりよい付き合い方を探し求めて行こうと思います。


  1. Web ACL単位でも課金が発生するためコスト削減の意味合いもあります
  2. これがないとセキュリティ診断からの通信はXSSSQLインジェクションなどの攻撃を含むのでWAFで遮断されRailsアプリケーションまで到達せず診断できないのです…

ChatGPTのAPIをサービスに組み込んでみました

こんにちは。

株式会社Azoopで開発をしている真面目で誠実なエンジニアのokamuraです。
ChatGPTを使って何かできないかな?と思っているところに、ちょうど活用できそうな場面に遭遇したので、サービスに組み込んでみました。

どんなサービスに組み込んだ?

現在Azoopで提供しているトラッカーズマネージャーという運送会社向けのサービスに組み込みました。

具体的な機能の内容

トラックの修理整備記録データをシステムに入力する際に、システム側に用意されている修理整備箇所カテゴリのどれに該当するかを推測する、という機能です。

図のように、修理整備記録の請求書に記載されている内容を見て該当するカテゴリを選択するのですが、専門知識を持ったユーザでないと選択が難しい場合があります。

そのような場合に、質問するとどのカテゴリに入るか推測して教えてくれる補助機能があると便利そう、という要望がカスタマーサクセスの方から出ていました。

ChatGPT使えそう!と思ったので、質問するとどのカテゴリに入るか推測して教えてくれる補助機能を、ChatGPTのAPIを組み込んで作ってみました。

機能としてはシンプルで、単語を受け取って、ChatGPTのAPIを使ってカテゴリを推測し、推測した結果を返す、というものです。

実装の内容

ChatGPTのAPIでは、system、assistant、userという3種類のロールでメッセージを渡すことができます。

system
  • ChatGPTに役割や指示を与える
assistant
  • ChatGPTとの今までのやりとりを与える(今までのやりとりを踏まえた上で答えてくれる)
  • APIではインタラクティブなやりとりはできず、過去のやりとりからの文脈を判断して答えることができないので、過去のやりとりが必要な場合に必要となる
user
  • ChatGPTにユーザとしてのメッセージを与える

 

今回は、assistantは不要だったので、systemとuserのロールでメッセージを渡しています。

systemロールでは、下記のような指示をいくつか与えています。

  • あなたはトラックの修理整備について詳しいです
  • 与えられる単語に対して、どの選択肢が近いかを「AAA、BBB、CCC」の選択肢の中から答えてください。

userロールでは、ユーザから入力された単語を与えています。

まとめ

以上が、ChatGPTのAPIをサービスに組み込んでみた例でした。

今回は部分的に小さい規模でAPIを組み込んだのみでしたが、ChatGPTの一歩目としてはやれて良かったと思います。

今後もChatGPTの使いどころ探していきたいです。まだ公式のAPIは出ていないようですが、Code Interpreterもいろいろ使いどころありそうで気になります。

QuickSight余話

どうも、Azoopでエンジニアとして末席に名を連ねている杉本です。

最近社内の一部でグルメ部なるものを立ち上げる機運が少しずつ高まっていて、お財布の中が心配になってます。

今日はAWSで利用できるBIサービスの1つ、Amazon QuickSightのお話をしたいと思います。 弊社では、お客様の車両に関連する情報から車両の維持や運用にかかるコストを可視化し、お客様に現状をより理解しやすい形でご提供するためにQuickSightを利用しています。

今回QuickSightのお話をするにおいて、一度全体の機能をさらっとご紹介しようかと考えていたのですが、どうしてもボリュームが多くなってしまうので実際にQuickSightを利用した機能をリリースするまでの間で困ったり詰まったりしたポイントに絞って、困り具合とともにご紹介していこうと思います。

開発開始からリリースまでで困ったこと・詰まったこと

データソース大量登録問題(困り具合: ★☆☆)

データセットを作成する際、必ずデータソースを求められます。 最初の頃、いくつかのデータセットを作成しようとデータセットの作成画面にアクセスしていました。そして、都度RDSへの接続情報を入力していました。 時間が経ち、ふとあるとき新たしいデータセットの画面で下へスクロールすると、データセットと対になったデータソースが大量に発生していることに気づき…。

すでに作ったデータセットと同じデータソースを使う際は、データソースの一覧の下の方にある 既存データソースから から選ぶと、データソースが増殖しなくていいかもしれません。

いつの間にかデータソースが大変なことに

ユーザー権限数上限問題(困り具合: ★★★)

お客様のアカウントを作成する際、契約によってはQuickSightのダッシュボードを閲覧できるようにするためにQuickSightのユーザーも同時に作成し、ダッシュボードに対してユーザーへの閲覧権限を付与していました。 あるとき、エラーが出てアカウントが作成できない!と問い合わせをいただき、調査したところ権限数の上限に達して付与できず、アカウント作成の途中でロールバックしていました。 実は分析・ダッシュボード・テンプレート・テーマなどは、最大で100個のプリンシパルと共有できるとあり、裏を返せば 上限を超えると権限付与ができなくなる という落とし穴があります。

これらはグループ機能またはフォルダ機能などを使って解決可能です。弊社ではグループ機能を利用しています。

参照: https://docs.aws.amazon.com/quicksight/latest/APIReference/qs-api-permissions.html#qs-api-permissions-best-practices

ステージングと本番の同期問題(困り具合: ★★☆)

開発またはステージング環境で分析・作成のトライアンドエラー・もし問題ないと分かれば本番環境にも… 分析を環境ごとに分けたいという要望は普通にあると思います。別環境で作った分析を本番環境に移行するには、グラフ1つ1つの設定をコピーし、テーマを設定して…というのは、漏れなく移行するのは難しい話です。

これもいくつかやり方があるのですが、弊社ではAPIからテンプレート機能を利用してコピーする方法を取っています。

ざっくりとしたイメージ図です

画面とQuickSight上の数値ずれ問題(困り具合: ★★★)

すでにサービス上に集計された画面があり、その集計された数値をダッシュボードで表示したいとなったとき、データの構造が違うために取得する条件が変わり同じ数値にならないときがあります。そういう場合調査が大変なこともあり、アプリケーションやフレームワークなど見えないところでよしなにしてくれているものがあればなおさら原因が見えづらいことも。

こればかりは最初からデータの取得ロジックを揃えておいたり、データソースをファイルベースにしてしまい、ロジックをアプリケーション側で使い回すなどといった工夫が必要かもしれません。

テーマ間違っていじっちゃった問題(困り具合: ★☆☆)

分析を複数人で編集しているときなどで起こりうる話なのですが、共有されていないテーマを別の人が設定していたときに、自分が間違えて自分のマイテーマをクリックした瞬間テーマが切り替わり、さらに分析の自動保存が実行されて戻せなくなったりすることがあります(実際ありました)。

テーマを共有してもらえばなんとかなるかもしれませんが、そうではない場合はコンソールやAPIからテーマを取得して自分に共有したりなど少し面倒な対応が必要になるかもしれません。

QuickSightを運用する際、見えない仕様で困ったりコピーする機能が確立されてなかったりで色々と考えなければならない問題がいくつもあります。慣れが必要なのは言うまでもないですが、そういう状況になったときにこの記事が一助になれば幸いです。

このuseEffectは不要だとおれのサイドエフェクトが言ってます

すいません、そんなサイドエフェクトは持っていません・・・

ワールドトリガー面白いですよね。

こんにちは、株式会社Azoopで主にトラッカーズマネージャーの開発をしている中山です。

TL;DR

Reactの公式ページリニューアルされてとても良きです・・・

react.dev

駄文

少し前にReactの公式ページがリニューアルされて、面白そうな学習ページが増えたり、練習問題がたくさん用意されたりして、React学習の敷居が少し下がったなと感じました。

非常にいいページなので、紹介したくブログを書きました。

ぜひ見てください!!!(完)

react.dev

とするのは乱暴なので、自分が見て気に入ったページの

You Might Not Need an Effect – Reactの内容を一部、感想を添えて紹介したいと思います。

PropsやStateに基づく、Stateの更新

Updating state based on props or state

下にこのケースに該当するコードの例を置いています。

あるStateが更新された際に、別のStateを更新したい例です。

このケースは例くらい分かりやすい状態だとあまり発生しないかなと思います。

Stateの数が増えてきて、ソースコードが複雑になってきた時に発生しうるかなと思います。

  • useEffectの中でsetStateを行っている
  • useEffectの第2引数に変数が多く並んでいる

上記の場合は、このケースに該当するかもしれない・・・と疑ってソースコードを見ています。

例) useEffect削除前

例) useEffect削除後

Propsが変化したときに、Stateの値をリセットする

Resseging all state when a prop changes

下にこのケースに該当するコードの例を置いています。

あるPropsやStateの変化に応じて、フォームの値をクリアしたい例です。

これは過去、自分もuseEffectを使って書いてしまったなと反省しています😇

コンポーネントの状態をkeyを使ってリセットできるということを知らなかったが故の苦肉の策でした・・・

  • useEffectの中でsetState(""), setState(null)などを行っている

上記の場合は、このケースに該当するかもしれない・・・と疑ってソースコードを見ています。

例) useEffect削除前

例) useEffect削除後

 

送りコード2023春が開催されました

最近寒暖差が激しくて少しダレています。どうも、Azoop杦本です。

先月、数ヶ月に1度開催されている送りコードというものが開催されました。今回が第3回となります。 送りコードというのは以前の記事にも記載されている通り、エンジニアメンバー全員が普段の業務から離れて技術的負債の解消に集中する 日となっております。詳しくは下の記事をご覧ください。

tech.azoop.co.jp

重厚なメソッドの分解、フレームワークの更新、不要なファイルの削除、今まで見て見ぬ振りをしてきたものの対応、自動テストのチューニング、見えづらい問題の可視化など、今後もシステムを運用する上で必要な作業を2日間行い、最後にエンジニア全員で集まって作業内容の発表と質疑応答を行いました。

カジュアルに昼食を食べながら始まった送りコードですが、今回は私の希望で寿司となりました。いいですよね、寿司。

発表の前に乾杯!ただしノンアルコールです。

弊社エンジニアグループでは、不定期で読書会なるものを朝会の後に開催しているのですが、そこでリファクタリングデザインパターンの知識を改めて学び、ディスカッションしています。そうやって得た知見を送りコードの場でリファクタリングをする際に実践するなど、うまくこの機会を利用している人もいました。

運用していくとどうしても負債がたまっていくアプリケーションの整理、皆様はどのようにされてますか?