TECH PLAY

株式会社ラクス

株式会社ラクス の技術ブログ

919

こんにちは! 技術広報課のyayawowoです。 今回は、 ラク スのPdMが所属している製品管理課が どのような目的と目標を持った組織なのか を詳しくご説明します。 2021年10月にPdM組織「製品管理課」を新設してから3年目となる今、 どのような役割でプロダクトの価値を上げているのでしょうか 。 PdM組織「製品管理課」を新設した背景と経緯 背景 「あるべき姿」に向けて 実際に実行した8つのこと 現在のミッション/ビジョン/組織の役割 新規PRJでのプロダクトへの貢献 AIの製品活用PRJ 楽楽シリーズブランド統一PRJ まとめ ラクスのPdM組織で働いてみませんか? PdM組織「製品管理課」を新設した背景と経緯 背景 2021年10月、東京開発部門の横断組織としてPdM組織「製品管理課」を新設しました。 まずは、製品管理課を新設した背景をご説明します。 【プロダクト開発体制:製品管理課の存続前】 製品管理課の新設前、上記の通り、ビジネスサイドに所属する「製品企画」という組織がPdMとPMMの両方の役割を担っていました。 まずは、このプロダクト体制での課題を理解することが必要です。 このようなプロダクトチーム体制の場合、プロダクト開発にてよく言われている課題は以下の通りです。 ラク スのPdMが経験を基にまとめました。 開発側の課題 こうして欲しいという要望(HOW指定)が多く、顧客の声や課題がぼんやりしている 開発する項目の優先度が属人的で納得感が十分に持てない システムが肥大化し品質維持のためにかかる 工数 が多く、新規機能開発に時間がかかる 品質が安定せず、バグの発生都度高く、その対応に追われ開発が計画的に進まない 問い合わせや仕様確認等が多く、開発に専念できない ビジネスサイド側の課題 開発側へしっかり要望が伝わらず、何度もやり取りや資料のやり直しが発生する 思った通りのタイミングでリリースができないことがある バグが発生して、その対応に追われている もっと多くの要望を実現して、色々試したいがそれが十分にできない では実際、社内の状況はどうでしょうか。 現状把握を行うため、製品管理課に所属するPdMが開発/ビジネスサイド側のキーマン数名に ヒアリ ングしました。 ヒアリ ング結果が以下になります。 ポジティブな意見 品質が高い、軽微なバグはあるものの致命的なものは皆無 開発プロセス がしっかりしているため、手戻りは少ない 各組織の目標や役割が明確である ネガティブな意見 事業部から開発へ課題や要求が上手く伝わらず、互いに効率が悪い部分がある 10年以上の運用しているシステムであり、開発規模も大きくなり 計画通りに進める難易度が年々あがっている 開発する項目の優先度を決める基準がややあいまいな部分がある ポジティブな意見としては、役割分担でしっかりと品質が高いプロダクト開発ができているという点が分かります。 一方、ネガティブな意見として前述したプロダクト開発にてよくある課題と同様の意見と、15年弱運用してきて一気に成長したプロダクトならではの課題が上がっています。 「あるべき姿」に向けて 現状把握後、 ヒアリ ング内容の課題が問題であるかをはっきりすべく、目標設定とあるべき姿を定義しました。 ◆ 何から決めたのか  1. Missionの設定  2. KGI・KPI/コンテキストの設定 まずは、Missionの設定とKGI・KPI/コンテキストを決めました。 但し、最初から確定するには難しいため、下記ポイントを注意・意識しながらも変化を前提としております。 ◆ 設定時に注意・意識したポイント  1.いずれも変化することを前提に設定  2.「KGI・KPI/コンテキスト」はいきなり理想の追及にはせずに段階を踏むようにした  3.初期の「KGI/コンテキスト」は以下を意識   ・プロダクト開発チームへ価値や貢献がもたらされ、半年以内で変化をさせられる   ・メンバーの現時点での強みが活かせるものにする メンバーの強みを活かして変化や貢献できることから、設定した形になっております。 ◆ 【目標設定】あるべき姿 では、製品管理課の新設時に設定した目標設定をご紹介します。 Mission ビジネス、エンジニアリングの架け橋となりカスタマーサクセスに導く、売れる製品を実現する KGI・KPI/コンテキスト 【ステップ1】開発組織への貢献 開発者がより開発に集中できる環境の提供 【ステップ2】ビジネスサイドへの貢献 PMMがより事業戦略やGTMに集中できる環境の提供 【ステップ3】顧客、プロダクトへの貢献 PdMがより直接的に製品へ貢献できるようにする 製品管理課の新設前は、上記のステップ1〜3を順次進めていくことで、開発組織内外から見てもどのようなステップで進めているかを明確にしておりました。 ラク スのPdMは開発組織に所属しているため、まずは開発組織への貢献を第一に置きました。 次に、ビジネスサイドとPMMがより事業戦略やGTMに集中できるような環境の提供、最後は、直接的に顧客製品への貢献ができるようなステップを踏みました。 実際に実行した8つのこと では、実際に新設時〜現在までに実行した「KGI・KPI/コンテキスト」の3ステップを細かくご紹介します。 前述にもある通り、まずは開発組織への貢献を第一に考えて実行しております。 【ステップ1】開発組織への貢献(1年目) まずは、開発組織への貢献とPMMが得意としていない業務の巻き取りです。 製品管理課の新設前は、PRD(Product Requirements Document)の作成をPMMが担当しておりました。 開発からの信頼獲得とPMMの苦手業務を移管するために、PRDの作成はPdMが作成することに変更し、PdMの観点でPRDを作成することにしました。 これにより、開発組織向けの資料となり、開発の要件定義以降のフェーズの効率化に繋がりました。 【ステップ2】ビジネスサイドへの貢献 (2年目) PdMのあるべき姿を踏まえ、PMMとPdMの役割分担も明確にしました。 実際にどういった開発案件をしていくかの決定フローを含め、PMMと相談をしながら決めていきました。 案件創出を担う役割をPMMからPdMに切り替え、PMMとPdMの業務の無駄を無くすことで効率化に繋げました。 【ステップ3】顧客、プロダクトへの貢献(3年目) PdMが一番重要としている、プロダクトに価値をより出していく部分になります。 当時の課題に対して打ち手は以下の通りです。 ①プロダクト開発計画の作成 問題 :年間でどのような開発を進めるのかが明確になっていない 打ち手 :「プロダクト開発計画の策定」を明確にすることで、開発の効率化を目指した ②PdMでの顧客解像度を向上 問題 :PdMの顧客解像度が低く、一次情報が取れていない 打ち手 :価値のあるプロダクト開発を目指し、「Discovery( ディスカバリー )」の領域をメインとした業務を遂行した ラク スの代表的プロダクトである 楽楽精算 は、ステップ3まで取り組むことができました。 今後は、他プロダクトにもこの取り組みを活用することで、より高いレベルでPdMができる可能性があるため、担当する対象のプロダクトを増やしていく方針です。 現在のミッション/ビジョン/組織の役割 では改めて、現在の製品管理課のミッション/ビジョンと組織の体制/役割をご説明します。 ■ミッション ビジネス、エンジニアリングの架け橋となり、カスタマーサクセスに導く、売れる製品を実現する ■ビジョン テク ノロ ジー ・UIで最高のUXを製品にもたらし続ける 【プロダクト開発体制:現在】 製品管理課のミッションは、課の立ち位置を踏まえた上でビジネス側にPMM、開発側にPdMがいることで 『ビジネス、エンジニアリングの架け橋となり』 、開発本部が掲げているミッション「顧客をカスタマーサクセスに導く圧倒的に使いやすい SaaS を創り提供する」の 『カスタマーサクセス』 と、PMMが所属する製品企画のミッション「ユーザーニーズを捉えた、売れる、選ばれ続ける製品を創る」の 『売れる製品を創る』 を踏まえた上で考えられました。 また、ビジョンの 『テク ノロ ジー ・UIで最高のUXを製品にもたらし続ける』 はユーザ体験を重視し、継続的に製品にもたらす状態にしておくという思いで掲げています。 続いて、「プロダクトの4階層」から見たときの製品管理課のPdMの役割を紹介します。 ■PdM組織の役割 緑:PMM(ビジネスサイド)が担っている役割 紫: PdM /PMMと合同で担っている役割 青: PdM が担っている役割 薄い青:開発/デザイナー 一般的にPdMの役割は「Discovery( ディスカバリー )」と「Delivery(デリバリー)」の領域があると言われていますが、 ラク スのPdMは、「Discovery( ディスカバリー )」のWhy、Whatに役割が集中しています。 製品管理課を立ち上げた際、開発側に属しているPdMが得意分野としているプロダクト、テク ノロ ジー 、顧客を紐づけた「Discovery( ディスカバリー )」を巻き取り、PdMの強みを活かしているためです。 これにより、ビジネスサイドにいるPMMは事業戦略やGTMに集中できる環境となり、開発側の生産性も上げることができました。 また「Delivery(デリバリー)」領域は、PdMとてはPMのような振る舞い等での役割は担っておらず、以下のような観点に対し、レビューアとしての役割を担っています。 顧客の要求を満たせているか プロダクトが顧客に価値を出せているか 等 このように、組織としての役割分担を明確にし、各フェーズでの専門性を高めることで、より効果的なプロダクト開発を可能としています。 ◆ 関連記事 career-recruit.rakus.co.jp 新規PRJでのプロダクトへの貢献 今後、製品管理課は新規PRJでプロダクトへの貢献に力を入れていきます。 今回は、代表的な2つについてご説明します。 AIの製品活用PRJ 製品管理課が携わっている楽楽精算はこれまでAIの活用をしていましたが、しっかりと発信やロードマップを示せていませんでした。 ◆ 楽楽精算のこれまでのAI活用 ・ 「楽楽精算」が最新のAI機能を活用した領収書読み取りアプリをリリース|「楽楽精算」 ・ 「楽楽精算」v10.5を提供開始。業務負荷が高い”紙請求書受け取り/処理の効率化”を支援し請求書の読取精度”99.9%”以上を実現|「楽楽精算」 楽楽精算は1.7万社以上のお客様に導入されており、お客様の苦労や成功体験が利用実績としてデータに蓄積されています。 今後、このデータをAI活用し、現在導入しているお客様のみならず、新たに導入されるお客様へも価値を提供できるように新しいプロジェクトにも力を入れていく予定です。 楽楽シリーズブランド統一PRJ 2つ目は、楽楽シリーズブランド統一に向けてのPRJです。 本PRJは、ブランド統一のためにUI/UXについてもシリーズ間で ガイドライン を一部揃え、複数導入したお客様に対して、それぞれの製品が最適なUXを提供できるようにすることを目的としています。 今後、こういった新規取り組みをプロジェクト化し、遂行していく予定です。 製品管理課の今後に乞うご期待ください! まとめ PdM組織「製品管理課」の紹介記事はいかがでしたでしょうか? 有難いことに ラク スのプロダクトは年々利用者が増え、会社規模も大きくなってきております。 製品管理課は、プロダクトの価値を上げるためにPdM組織としての目的/目標/役割を明確にし、顧客解像度上げることでプロダクト開発の生産性を上げているのをご理解いただけたのではないでしょうか。 また製品管理課のPdMは、弊社プロダクトの製品開発力や 組織力 の強みを社外に発信するべく、定期的に外部イベントに登壇しております。 直近では、「物流版 AWS 」をコンセプトに物流プラットフォームを展開する「オープンロジ」様と合同で、 プロダクトマネジメント の在り方についてディスカッションを行います。 オフラインイベントのため、イベントに参加するPdMやPdMを目指す方との交流ができますのでお気軽にご参加ください! 開発エンジニア、デザイナー、マーケターもお待ちしております! ◆ PdMイベントのご案内 お申込みはこちらから! rakus.connpass.com ラク スのPdM組織で働いてみませんか? AI・デザイン・ 経理 分野での ドメイン エキスパートついてはPdMの経験がなくても問題ございません。 しっかりとPdMの部分を支援や成長できるように努めてまいります! 少しでもご興味ある方がいらっしゃいましたら以下URLをご確認ください。 career-recruit.rakus.co.jp 製品管理課は、これらの取り組みに共感/情熱をもって一緒に働いてくれる方を募集しています! 最後までお読みいただき、ありがとうございました。 ◆ 関連記事のご案内 クライス&カンパニー様の Podcast で、PdM組織マネージャーの稲垣が及川 卓也様にインタビューいただきました! 顧客・事業貢献への思いや展望を語っております。是非ご覧ください! 「 ディスカバリー にとことん集中できる環境で、企業のバックオフィス業務を効率化するプロダクトを。」 www.kandc.com 開発本部のミッションに込めた想いをエンジニア/デザイナーが発信した、 「RAKUS Tech Conference 2024」のまとめ記事です!是非ご確認ください。 tech-blog.rakus.co.jp
アバター
はじめに はじめまして、楽楽精算のサポートエンジニアを担当している梅田です。 私たちのチームは、お客様がサービス利用におけるお困り事を解決できるよう、エンジニアの立場からサポートを行っています。 本記事では、生成AIを活用して問い合わせ対応業務を効率化し、回答までにかかる時間を75%削減した取り組み、具体的な活用方法や効果、AI活用のポイントをお伝えします。 はじめに サポートエンジニアの概要 サポートエンジニアの役割 サービスデスク 問題管理 リリース管理 サポートエンジニアの連携先 サポートエンジニアの課題 問い合わせ対応における問題 問い合わせ対応における課題 サポート業務改善に生成AIの導入 改善に生成AIを選定した理由 生成AIを使った問い合わせの効率化 計画 工夫 成果 更なる改善   サポートエンジニアの概要 サポートエンジニアの主な業務の1つはお客様からの問い合わせ対応です。 基本的には、お客様からの問い合わせはカスタマーサクセスで回答をしています。 ただし、技術的な内容などについてはカスタマーサクセスからエンジニアへ エス カレーションが上がってきます。 サポートエンジニアは、このカスタマーサクセスから上がってきたお客様からの問い合わせの エス カレーション対応を行っております。 サポートエンジニアの役割 サポートエンジニアが エス カレーション対応を通じて担当している役割は、 ITサービスマネジメント のベストプ ラク ティスである ITIL の フレームワーク に基づいて、以下の3つに分類できます。 サービスデスク サービスデスクの目的は、問い合わせや問題報告に迅速に対応し て、お客様に サービスを継続利用いただけるようにすることです。 ラク スの開発本部では顧客視点を重要視しています。 問い合わせ対応を迅速に対応することで、お客様が楽楽精算を利用して 経理 業務を円滑に実施いただけるようになるので、顧客視点の面からも重要な役割となります。 サポートエンジニアは、お客様からの問い合わせに対し、カスタマーサクセスから エス カレーションされた技術的な問題に対する初期調査を担当 しています 。 ソースコード レベルでの解析が必要な場面などでは開発チーム と連携し、早急に 対応して 、お客様がサービスを継続利用できるようサポート しています 。 問題管理 問題管理の目的は、 繰り返し発生するシステムの問題を特定し、その根本原因を解決することです。 サポートエンジニアは、 暫定対応が完了した問い合わせに対して、恒久対応の実施可否や対応時期について開発チームと連携し、対応を調整を行います。 恒久的な対応が適切なタイミングで実施され、お客様の問題が解決されることで システムが安定し、お客様が安心してサービスを利用できるようサポートしています。 リリース管理 リリース管理の目的は、 計画的かつ円滑な機能リリースを行うことにより、新規または変更されたサービスをお客様が問題なく利用できるようにすることです。 サポートエンジニアは、 リリースプロセス全体の調整や管理、特にリリースに向けた準備やテストの実施、リリース後のシステム動作確認を担当しています。 リリースが計画した通りに行われることで、お客様へ新しい機能や改善が円滑にリリースされ、お客様の業務がより効率的に進められるようサポートしています。 サポートエンジニアの連携先 「サポートエンジニアの役割」の中でも登場しておりますが、サポートエンジニアはお客様へ安心して利用できるサービスを提供し続けるために 下記をはじめとするチーム と連携して います。 サポートエンジニアの連携先 サポートエンジニアの課題 現状サポートエンジニアは少人数でカスタマーサクセスからの問い合わせに対応しており、迅速な回答ができていない時が発生していました。 問い合わせ対応における問題 楽楽精算の利用社数が増える中で、当初想定しきれなかったカスタマイズをしてご利用いただくケースも増えてきました。 カスタマーサクセスから エス カレーションされた内容について高度な調査が必要になる場面も増えてきて、以下のような 問題が出てきました。 迅速な対応の難しさ カスタマーサクセスからの問い合わせや緊急の問題報告に対して、問い合わせの内容によっては調査や暫定的な解決策の提供に時間がかかることがあります。 スパイク的な問い合わせ対応 スパイク的に問い合わせが重なる場合、サポートエンジニアの対応が追いつかなくなることがあります。 一貫した対応品質の維持 問い合わせ ごとに適切な対応を行うためには、過去の事例やナレッジベースを参照する必要がありますが、手動での検索や分析には限界があります。 問い合わせ対応における課題 問い合わせ対応 の 問題 を見直したところ、主に問い合わせ対応の調査で手動作業や解析に時間がかかっていることが 課題だとわかりました 。 サポート業務改善に生成AIの導入 これらの作業を効率化することで 課題 解決できると考え、生成AI導入を決めました。 改善に生成AIを選定した理由 前述のように課題解決のために生成AI導入を決めましたが、選定理由を正直に言えば、ChatGPTのような生成AIが持つ革新性に強く惹かれたからです。 ChatGPTに初めて触れた際、生成AIが質問に対して即座に的確な回答をするだけでなく、関連する知識や背景情報を自然な対話形式で提供してくれる点に非常に感銘を受け、単なる情報提供を超えた可能性を秘めていると感じました。 また、 エンジニアとして新しい技術に触れ、その可能性を試したいという思いがありました 。 加えて、 ラク スの行動指針であるリーダーシッ ププリン シプル「小さく試して大きく育てる」に基づき、まずは 問い合わせ対応 に適用し、成功すれば他の領域にも展開できると考えました。 生成AIを使った問い合わせの効率化 サポートエンジニアの業務に生成AIを導入することで、問い合わせの効率化を実現しました。 サポートエンジニアが問い合わせの効率化を計画し、どのような工夫で生成AIを活用し、成果を出すことが出来たのかを説明いたします。 計画 現状(図:GPTsを使う前の問い合わせ対応)の問い合わせ課題 を解決するためにChatGPTのGPTsを活用する計画を立てました。 GPTsは、 自然言語処理 ( NLP )技術を利用してユーザーからの問い合わせを解析し、適切な回答を生成する機能を持っているため、カスタマーサクセスからサポートエンジニアへの エス カレーション後に行う調査時間を短縮するのに最適であると判断したためです。 GPTsを使う前の問い合わせ対応 現状の問い合わせ対応における課題 迅速な対応の難しさ スパイク的な問い合わせ対応 一貫した対応品質の維持 工夫 計画に基づき、GPTsを活用したカスタマーサクセスからサポートエンジニアへの エス カレーション後に行う調査を自動化しました。 この調査の自動化を効果的に行うため以下のような工夫を実施しました。 複数視点の導入 回答精度を向上させるため、AIに複数の視点を持たせる手法を導入しました。AIが異なる観点から分析を行わせることが狙いです。実際にAIの中で議論を重ねることで、最適な回答を導き出すことができ、精度の高い回答が得られるようになりました。 GoogleDriveAPIによる学習 GPTsにはファイルをアップロードして、追加で知識を学習させる「knowledge」機能がありますが、この機能にはファイル数やファイルごとの容量に制限があります。ChatGPTを Google Drive と連携し、指定フォルダ内のドキュメントを参照させることで、楽楽精算の仕様やマニュアル、過去の問い合わせナレッジに基づいた回答が得られるようになりました。 GPTsへの学習を自動化 調査結果の精度を持続的に向上させるため、過去の問い合わせデータやナレッジベースを整理し、データのクロールと学習プロセスを自動化しました。これにより、 GPTs は継続的に新しい情報を学習し、検索精度と解析能力を向上させています。 成果 GPTs機能を活用することで、サポートエンジニアの問い合わせ対応業務の効率化(図:GPTs導入後の問い合わせ対応)が実現できました。 GPTs導入後の問い合わせ対応 迅速な対応と問い合わせ対応の効率化 関連する過去事例や情報を迅速に検索・参照できるようになり、とある対応では従来よりも調査にかかる対応時間が75%削減できました。 対応品質の向上と エス カレーション件数の削減 GPTsを活用することで、問い合わせ内容を複数の視点から解析できるようになり、ある種の問い合わせ対応においては一貫して高品質な対応が可能になり開発チームへの エス カレーション件数が50%削減できた結果、開発チームの負担も軽減できました。 スパイク的な問い合わせ対応の平準化 サポートエンジニアの調査時間の削減と開発チームへの エス カレーション件数が削減できたことで、スパイク的な問い合わせにも効果的に対応できるようになり、問い合わせ対応の滞りを減少させることができました。 更なる改善 サポート業務への生成AI導入は初期段階として上々の成果を上げました。 これですべての課題が解決できたわけではなく、まだ改善の余地が残っています。 今回は 問い合わせ 対応に GPTs機能 を使用しましたが、今後は他の業務にも GPTs を活用してさらなるお客様へのサービス品質向上を目指していきたいと考えています。
アバター
8/7(水)にRAKUS TechConference(以下TechCon)が開催され、盛況のうちに閉会しました。本記事ではその様子を、TechConを開催する目的や背景、当日発表資料なども交えながらご紹介します! TechConとは? TechConの開催目的 今年のテーマは「顧客志向」 ラクスの開発組織にとって「顧客志向」とは なぜ「顧客志向」をテーマに選んだのか? イベント概要 発表の紹介 「顧客志向」の開発組織 マルチプロダクトでのプロダクトマネージャーのリアル 拡大するマルチプロダクトSaaSの顧客理解にデザイン組織はどう取り組んでいるか 急成長する大規模プロダクト開発のマネジメント課題とアプローチ パフォーマンス向上とリソース管理のためのアプローチ 急成長するサービスを支えるためのインフラ戦略 楽楽精算のQA改革~楽楽精算でのQA専門組織の実践と成功事例 新たな顧客課題に挑む17年目の進化とモダナイゼーション クロージングトーク 終わりに TechConとは? TechConは、 ラク スの開発組織である開発本部が主催する、年に一度の大型イベントです。2022年に初開催し、今年で3回目を迎えました。 毎年、各チームがテーマに沿って取組みを発表する形式で開催しています。 TechConの開催目的 TechConは、当社のエンジニアやデザイナーが日々の業務を通じて得た独自の知見を発信することで、当社の開発組織やカルチャー、 開発プロセス 、利用技術について広く知っていただくことを目的としております。 また社内のエンジニアにとっても所属する組織の文化を改めて認識する機会とし、士気を高める場にしたいという目的もあります。 今年のテーマは「顧客志向」 今年のテーマとして掲げたのは、 「顧客志向」 です。 ラク スの開発組織にとって「顧客志向」とは 私たち開発本部は 「顧客をカスタマーサクセスに導く圧倒的に使いやすい SaaS を創り提供する」 というミッションを掲げています。 このミッションを実現するためには、何よりも「顧客志向」が欠かせません。 ラク ス開発本部にとっての「顧客志向」とは 顧客を深く理解し、本当に必要な機能を見極めた上で開発を行うこと、また顧客フィードバックを迅速かつ的確に製品に反映させることです。 開発本部が「顧客志向」を徹底することは 提供価値を追求し選ばれ続ける製品を提供することであり ひいては 「ITサービスで企業の成長を継続的に支援する」という全社のミッション実現にもつながると考えています。 なぜ「顧客志向」をテーマに選んだのか? 「顧客志向の SaaS 開発組織」であることは、2000年代初頭から顧客視点を重視して開発してきた当社の強みです。 しかし、組織が急成長する中で、メンバー一人一人の顧客に対する解像度が低下するという問題にも直面しており、「顧客志向」の維持・向上という課題にしっかりと向き合わなければなりません。そこで顧客志向の維持・向上という課題に各組織がどのよう取り組んでいるか、現場のリアルな事例を紹介し、顧客志向を持って開発する重要性を参加者の皆様と共有する場にしたいと考えて、このテーマを選びました。 イベント概要 日時 :2024/8/7(水) 14:00-18:00 会場 :オンライン 参加費:無料 主催 : 株式会社ラクス開発本部 X ハッシュタグ : #RAKUSTechCon techcon.rakus.co.jp 【イベントメッセージ】 ラク ス開発本部は「顧客をカスタマーサクセスに導く圧倒的に使いやすい SaaS を創り提供する」をミッションに掲げています。 私たちは、2000年代初期の SaaS 開発時から徹底して顧客視点を大切にし、顧客のペインポイントを理解し、その解決に向けて様々な取り組みを行ってきました。一方、組織が急拡大する中で、エンジニア一人ひとりの顧客に対する解像度が低下するという課題にも直面しました。 本カンファレンスでは、私たちが直面した困難とその乗り越え方、顧客視点を保つための具体的な取り組みを、CTOやPdM・EM・エンジニア・デザイナーが現場のリアルな声でお届けします。 顧客志向の開発を重視し、真のカスタマーサクセスを目指す皆様に、私たちの知見とインスピレーションを少しでも共有できればと思っています。 発表の紹介 ここからは各発表内容の紹介です! 「顧客志向」の開発組織 登壇:公手 真之 [ 執行役員 兼 開発本部長] speakerdeck.com 👉概要 ラク スの開発組織の進化を振り返りながら、「顧客志向の開発組織」となるために取り組んできたことをお話ししました。 初期の ベンチャー 組織から機能別組織、そして現在の 事業部制 へと移行する過程で、組織が大きくなるにつれて、顧客の声を取り入れる難しさが増してきます。 今後も「顧客志向の開発組織」であり続けるために、共通認識を強化するためのワークショップ実施や、各チームで顧客視点を強化するためのアクションを行い始めていることも紹介しました。 マルチプロダクトでのプロダクトマネージャーのリアル 登壇:稲垣 剛之 [製品管理課 課長] speakerdeck.com 👉概要 ラク スのPdM組織がどのようにお客様、製品、 ステークホルダー と向き合い価値を出しているのか、現場でのやりがい、苦労、難しさのリアルをお話ししました。下記のようなテーマで、 ラク スならではの特徴を紹介しました。 ・PdM組織の役割、発足と拡張の経緯 ・ ラク スにおけるPdMの役割分担、日々の プロダクトマネジメント 手法 ・マルチプロダクトならではのチャレンジと楽しさ ・今後の課題と展望 拡大するマルチプロダクト SaaS の顧客理解にデザイン組織はどう取り組んでいるか 登壇:小林 肇 [プロダクトデザイン課 課長]    今村 沙穂理 [プロダクトデザイン課] speakerdeck.com 👉概要 プロダクトデザイン課がマルチプロダクト SaaS の顧客理解にどのように取り組んでいるかをお話ししました。特に、顧客課題を解決するUI/UX設計のために、顧客理解と ドメイン 知識が重要であるということを、過去の失敗例や成功例を通じてご紹介しました。 さらに今後の課題として、顧客理解のさらなる深化と、それをチーム全体で共有することの重要性をお話ししました。 急成長する大規模プロダクト開発のマネジメント課題とアプローチ 登壇:高橋 康弘 [楽楽精算開発部 部長]    小宮山 和彦 [楽楽精算開発1課 課長]    涌井 友輔 [楽楽精算開発1課] speakerdeck.com 👉概要 楽楽精算開発チームが急拡大する中で発生した組織的課題、 開発プロセス 課題、技術的課題を紹介しました。 組織的課題としてはマネジメント負荷の増大、開発効率の低下が挙げられています。 これらの解決策として、役割の専門分化や技術負債の解消を目指したチーム構成の見直しが行われています。 開発プロセス 課題としては、サービス拡大により肥大化するコードに対する認知負荷が挙げられます。 分業化によりこの課題に対処しましたが、顧客視点の希薄化という新たな課題も生まれました。現在は顧客視点を強化するため、PdMとの連携や要求共有、顧客の声を直接聞く機会の提供や、仮説のモニタリングと検証に取り組んでいます。 技術的課題としては、技術的負債の解消が挙げられます。コードの リファクタリング やインフラの刷新に取り組むことで、生産性の向上と顧客価値の最大化を図る方針を紹介しました。 これらの取り組みを通じ、開発効率の向上と顧客ニーズに迅速に対応する体制の強化が期待されます。 パフォーマンス向上とリソース管理のためのアプローチ 登壇:牧野 寛知 [ ラク スライト クラウド 企画課]    上原 崇  [ ラク スライト クラウド 開発部] speakerdeck.com 👉概要 ブラストエンジンは、顧客のメールサーバ運用の課題から生まれた、 API 連携や SMTP リレーを通じて効率的なメール配信を可能にするツールです。 サービスを運営するうえでは、 API 処理の タイムアウト 、ユーザリソースの集中利用をはじめとする、パフォーマンスとユーザリソース管理の課題がありました。 これに対し、非同期 API 設計、レートリミットの採用、MongoDBの導入などの対策を実施しました。その結果、ユーザに安定したシステムを提供でき、利便性も向上できたことをご紹介しました。 急成長するサービスを支えるためのインフラ戦略 登壇:藤井 靖弘 [インフラ開発部副部長] speakerdeck.com 👉概要 ラク スでは急成長するサービスを支えるために、戦略的にオンプレミスを選択しています。 オンプレミスには、コストマネジメントと技術面の自由度を確保できるメリットがあります。セッションでは仮想化技術の導入によるラックコストの大幅な削減や、安定運用を実現するためのIOPS要件の最適化を紹介しました。 新技術導入によるコスト低減とレスポンス性能向上により、 顧客満足 を高める望ましいループを作っていく狙いをお話しました。 楽楽精算のQA改革~楽楽精算でのQA専門組織の実践と成功事例 登壇:金子 佳樹 [東京開発統括部 QA課] speakerdeck.com 👉概要 「楽楽精算」の品質保証(QA)専門組織の取り組みについて紹介しました。 楽楽精算のQA組織は、開発フェーズのテストだけでなく運用にも関わり、サービス全体の品質向上を目指しています。サービス利用社数の増加に伴い、開発とテスト・運用を並行して行うよりも、専門組織化するほうが効率的であるという背景があります。 顧客課題解決のためには、運用フェーズでしか得られないフィードバックも重要であり、それを開発に活かす フィードバックループ を確立する取り組みをお話ししました。 新たな顧客課題に挑む17年目の進化とモダナイゼーション 登壇:大塚 正道 [配配メール開発課 課長]    井上 良太 [配配メール開発課]    亀ノ上 孝雄 [フロントエンド開発1課] speakerdeck.com 👉概要 17年目を迎える「配配メール」は、従来のBtoB向けのメール配信サービスから マーケティング ・オートメーション機能を取り入れたサービスへ進化しました。より顧客に成果を実感していただくために、新たにリード獲得や商談獲得をサポートする機能が追加されました。 技術的には、従来の レガシーシステム のモダナイゼーションや、モダンなフロントエンド技術の導入に挑戦し、多くの一般ユーザーのアクセスに対応するためのフォーム機能やポップアップ機能を実現しました。これらの取り組みにより、サービスの進化と顧客価値の向上が図られています。 クロージング トーク 登壇:矢成 行雄 [大阪開発統括部 統括部長]    小林 肇 [プロダクトデザイン課 課長]    稲垣 剛之 [製品管理課 課長]    大塚 正道 [配配メール開発課 課長] speakerdeck.com TechConの締めくくりとして、エンジニア リングマ ネージャー、 プロダクトデザイナー 、プロダクトマネージャーによるクロージング トーク を行いました。 顧客志向を組織でどのように浸透させていくか ラク スならではの顧客志向の取り組み 生成AIが顧客体験や開発をどう変えるか など、最後まで熱い議論を交わしました! 終わりに 今回のTechConは開発本部のミッションに立ち返り、「顧客志向」をテーマに開催いたしました。昨年度より多くの方にご参加いただいたほか、参加アンケートからも取り組みに共感頂けたことが伺え、感謝いたします。 また社内からもポジティブなフィードバックが多く寄せられ、社内外共に意義深いものになったと振り返っております。 引き続き「顧客志向」重視の開発に取り組み、そこで得られた知見を次回のTechConでお届けしたいと思います! ◆ 関連記事 昨年度(2023年)の開催レポートは以下をご覧ください tech-blog.rakus.co.jp
アバター
概要 プロポーザル提出 採択から練習会まで 当日 感想 良かった登壇内容 概要 2024年8月22日~8月24日に開催された iOSDC Japan 2024 に、登壇者として参加しました。 本イベントは、日本の iOS やSwiftエンジニア向けの最大級のイベントの一つです。 このレポートでは、このイベントでの登壇経験についてご紹介します。 プロポーザル提出 iOSDCで登壇するためには、プロポーザルを提出し、主催側からの採択が必要です。 募集要項 にもあるように、 iOS やSwiftに限定せず、エンジニアにとって興味深いテーマであれば何でも構いません。 弊社でも有志で応募することとなり、私はこのようなイベントに応募した経験はなかったものの、挑戦することで経験を得られると考え、以下の3つのプロポーザルを作成しました。 なお、iOSDCでは初めて登壇する方向けに5分間のルーキーズLTという枠が設けられており、私のような初心者でも気軽に応募できました。 近距離撮影の新常識!iOSカメラアプリ開発におけるピンボケ対策の最前線 メモリ最適化を究める!iOSアプリ開発における5つの重要なポイント 実践!Flutter Add-to-app~既存アプリとの統合で見えたメリットと課題~ 採択から練習会まで 締め切りから約10日後、2番目の「メモリ最適化」に関するプロポーザルが採択されたというメールが届きました。 メールのタイトルに「採択」とあり、正直2度見してしまいました。 その後、メールに記載されていた必要事項の入力、チケットの購入(登壇者は無料です)、 トーク 可否の登録を行いました。 ※詳しい数字は公開できませんが、採択倍率はかなり高かったようです。 登壇資料を作成し、プレゼンの練習を進めていたところ、数日後に iOSDC Japan 2024 ルーキーズLT練習会 の案内メールが届きました。 ルーキーズLTの登壇者向けに本番の機材で練習ができ、経験者からのフィードバックを受けられるということで、少し不安もありましたが参加しました。 練習会には、私を含め5名の登壇者と主催の長谷川さん、スタッフ約10名が参加していました。 スタッフに見てもらえると思っていましたが、長谷川さんから直接プレゼンのフィードバックをいただけたのは非常に有益でした。 この経験のおかげで、本番でも不安を感じることなく登壇できました。大変感謝しています。 ※練習会は毎年開催されているようなので、ルーキーズLTに登壇する方には強くお勧めします。 ただし、カンペ無しで即座に登壇練習が始まるので、練習会の前に練習しておいたほうが良いです。 また、弊社のメンバーにも資料をレビューしていただき、大変感謝しています。 開催の一週間前からは1日2回、3日前からは1日3回程度プレゼンの練習を行いました。 当日 10:00頃に 西早稲田 の会場に到着し、受付を済ませると登壇者専用のネームプレートをいただきました。 私の登壇は17:55からだったので、17:00頃まで他のセッションを楽しむことができました。 ※特に印象に残ったセッションについては最後に紹介します。 当日の案内としては「受付を済ませて、登壇する時間になったら会場に来てください」といったものでした。 緊張しながら会場に向かうと、ペンライトが席に敷き詰められており、「これは何だろう?」と思っていたところ、スタッフの方に「ペンライトの色は何色が良いですか?」と聞かれました。 よく分からないまま「赤色」を選びました。(私はゲームなどでキャ ラク ターの目の色を赤にすることが多いので、ちなみにペンライトは登壇者応援用でした!) PCの接続チェック(外部映像出力の確認や、音声再生の確認)を行い、いよいよ登壇の時が来ました。 私も含めて8名のルーキーズLT登壇者が順番に登壇し、私の番が来たとき、会場はかなり暗く、観客の姿はほとんど見えない状態でした。 そのため、自分の話に集中できました。 練習では約4分50秒の内容でしたが、当日は4分30秒未満で終わってしまい、もう少しゆっくり話しても良かったと感じました。 登壇の様子 感想 iOSDCはコミュニケーションを重視しているイベントで、企業ブースではエンジニア同士の交流が活発に行われていました。 また、登壇内容も参加者が真剣に耳を傾けており、登壇者と直接話せる場も設けられており、エンジニアとして非常に楽しく刺激を受けることができました。 そんなイベントに登壇できたことを非常に嬉しく思いますし、大変良い経験となりました。 来年も登壇できるかはわかりませんが、ぜひ応募し参加したいと思います。 ※ただ弊社メンバーのご厚意で頂いた、たこ焼き引換券を使えなかったことだけが心残りです。 弊社メンバーがGETしたたこ焼き 良かった登壇内容 複雑さに立ち向かうためのソフトウェア開発入門 ソフトウェア開発全体における複雑さにどう対処するかについて、脳の認知リソースやワーキングメモリの観点から説明されていました。 タスクを細分化し、資料化して外に出す、チームメンバーに分散するなど、日常的に行っていることが脳の負荷分散に役立っていることがわかりやすく説明されていました。 また、登壇者のshizさんの話し方が講師のようで、とても聞きやすかったです。 月間4.5億回再生を超える大規模サービスTVer iOSアプリのリアーキテクチャ戦略 TVer が目指している アーキテクチャ の方向性についての説明でした。 長期間のリニューアルはリリースが遅れるリスクがあるため、モジュール分割とフィーチャーフラグを活用して段階的に公開する戦略が特に印象的でした。 審査が入るためリードタイムが発生するアプリのリリースにおいて、フィーチャーフラグで即リリースや ロールバック を制御する手法は非常に有用だと思いました。 快適な開発と高セキュリティを実現するCryptoKitを活用したCoreDataのデータ暗号化術 セキュリティを考慮したアプリ側で保持するデータの暗号化について、SQLCipherでのデータベース全体の暗号化や、CryptoKitでの個別データの暗号化など、実践的な手法が説明されました。 また、暗号化の際の 秘密鍵 の管理方法として、KeyChainを使って機種変更時に新しく生成するというアプローチが推奨されており、納得できる内容でした。 ◆ 関連ブログ 弊社から参加したメンバーのレポートは こちら! ぜひご覧ください。 tech-blog.rakus.co.jp
アバター
こんにちは。モバイル開発課の吉田です。 2024/8/22(木)~8/24(土)の3日間に渡り「 iOSDC Japan 2024 」(以下iOSDC)が開催されました。 そして今年度は弊社歴史上でも初のiOSDC登壇者として、当課メンバーが登壇しました! 応援も兼ねて当課メンバーもイベントに参加しました。 本ブログでは、当日の雰囲気やメンバーの印象に残ったセッションをお届けいたします。 iOSDCとは? 前夜祭 現地の様子 トークセッション メモリ最適化を究める!iOSアプリ開発における5つの重要なポイント 詳解UIWindow 座談会 「Strict ConcurrencyとSwift 6が開く新時代: 私たちはどう生きるか?」 ゼロから始めるiOSセキュリティ ~ OWASP Mobile Top10から学ぶ脆弱性対策 iOSアプリらしさを紐解く Kotlin MultiplatformでSaaS大規模アプリの生産性を向上させる技術的意思決定と導入効果を最大化するための取り組み さいごに iOSDCとは? iOSDCは iOS 関連技術をコアのテーマとしたソフトウェア技術者のためのカンファレンスです。 2016年の初開催から今年で9回目を迎えましたが、年々規模も大きくなり全国の iOS エンジニアからの注目度も非常に高いイベントとなっています。 当日コンテンツもメインとなる トーク セッションの他、ルーキーズLT大会、スポンサー企業ブースでのユニークな展示企画、交流を深める懇親会、果てにはネイルアートやフェイスペインティングなど初心者から熟練者問わず楽しめるコンテンツが準備されています。 今年度も引き続きオンライン( ニコニコ生放送 )+オフライン( 早稲田大学 西早稲田 キャンパス)でのハイブリッド開催でしたが、現地は今年の猛暑に負けないほどの熱気にあふれていました。 前夜祭 iOSDCの初日である8/22は、前夜祭としていくつかの トーク セッションが行われました。 その中でも今年の注目イベントは指示された動作をする Swiftコード をより短く書けた方が勝ち、という1対1の対戦コンテンツである「 Swiftコード バトル」! 予選から熱い戦いが繰り広げられ、前夜祭では決勝の優勝者決定までが配信されました。 内容はシンプルですが、ライブコーディング特有の難しさを感じられる臨場感がありました。 また、優劣が一目で分かるようにリアルタイムでバイト数が表示されたり、決勝では観覧者も急遽同じ問題に挑戦できるようシステムが整備されるなど、運営側の工夫も光り、非常に見ごたえがあり盛り上がりました。 現地の様子 翌日8/23からはいよいよ、朝からiOSDC本編の幕開けです! 当日も厳しい暑さでしたが、多くの方が足を運んでおり、お祭りのような賑わいを見せていました。 会場の様子と登壇ステージ スポンサー企業ブースでは iOS やSwiftにちなんだ趣向をこらした企画が催されており、和気あいあいと交流している姿が素敵でした。 企業ブース企画 また会場には色々なエリアに軽食やフリードリンクが提供され、キッチンカーも設営されるなど参加者への気遣いが感じられました。 改めて運営の方々がイベントを成功させるために毎年努力を重ねられているんだな、というのが伝わりました。 ドリンクと軽食サービス トーク セッション メインとなる トーク セッションは、会場4か所のブースでルーキーズLTも含めると合計91ともなる多種多様な トーク が行われました。 日頃オフラインイベントに参加する事は少ないのですが、やはり現地で直接聴講するとスピーカーの方や会場の熱量も分かりやすく、立て続けの移動で1日の終わりにはクタクタになりましたが、とても濃厚な時間を過ごすことができました。 ここからは、当課メンバーが特に印象に残った トーク セッションをご紹介させていただきます。 メモリ最適化を究める! iOS アプリ開発 における5つの重要なポイント fortee.jp speakerdeck.com 概要 当課メンバーの発表 昨今は機種性能向上により、ほとんど意識する機会が減ったアプリメモリ管理ですが、改めてそのテクニックを紹介 感想 そこまで意識しないでいいととはいえ、このようなハードに近い領域を前提知識として知っているかどうかでクオリティに差が出る事を再認識した セッション自体ではないが5分という枠の中で、終わりに近づくと サイリウム を振って合図するなど会場の一体感が伝わるようなルーキーズLTの雰囲気が楽しかった 登壇の様子 詳解UIWindow fortee.jp speakerdeck.com 概要 UIWindowについて、UIScreen、UIWindowScene、UIViewとの関係と各クラスの役割、またこれらのクラスが動作するときの細かい挙動を解説 感想 基礎的な内容だが、開発者として知っておいた方がいいセッションと感じた 開発で触れることのあるUIWindowと関連するクラスについて、どういった概念で作られたものなのかわかりやすい図とともに解説しているところが良かった 画面要素の表示順序が設定される仕様、全画面表示にしたとき特有の仕様など知っておいた方がいいことやSwiftUIからウィンドウサイズを取得する場合など学びの多いセッションだった 座談会 「Strict ConcurrencyとSwift 6が開く新時代: 私たちはどう生きるか?」 fortee.jp speakerdeck.com 概要 Swift 6におけるStrict Concurrencyの導入が、ソフトウェア開発にどのような影響を与えるかについて、座談会形式で議論 感想 Data raceとRace conditionの違いについて図で説明されていて分かり易かった Data IsorationについてIsoration Domainごとの具体的なコード事例など交えながら説明があり分かり易かった Concurrencyへの移行を始めるのにおすすめのレイヤーとData raceの原因ごとの具体的な手法について言及されており学びが多かった ゼロから始める iOS セキュリティ ~ OWASP Mobile Top10から学ぶ 脆弱性 対策 fortee.jp speakerdeck.com 概要 モバイル開発を行うにあたって、よく遭遇するセキュリティリスクを例に、その内容と対策を紹介 感想 モバイル アプリ開発 におけるセキュリティの重要性を改めて認識できた。特に、クライアント側の端末で動作するアプリにおいて、センシティブな情報(パスワードや個人情報など)の取り扱いには、細心の注意が求められることが強調されていた点が印象的だった アプリごとに作成された サンドボックス 領域へのアクセスも決して不可能ではないという点、リリースビルドであってもコード解析は可能であるという事実から、セキュリティ診断を行う際に Apple の仕組みに頼り切った判断は危険だと認識できた これらの点から、そもそもセンシティブなデータはアプリ側に置かない方が良いという結論に自然と至った。できるだけクライアント側ではなく、サーバー側でデータを管理し、必要に応じて最低限の情報のみを端末に保存するというアプローチが、より安全なのだと強く思った iOS アプリらしさを紐解く fortee.jp 概要 iOS アプリのデザインにおける「 iOS らしさ」とは何かというテーマについて、Human Interface Guidelinesや Apple 純正アプリ等から分析した結果について紹介 感想 デザインがユーザへ与える情報量は多く、適切なアニメーションやUIの採用がユーザー体験の向上に与える影響は大きいと感じた Apple における「直感的」というワードは切っても切れないもので、現実世界の挙動を模倣したデザインの採用もその役割を担っていると感じた ハーフモーダルを引っ張って項目を探すという動作は、引き出しから物を探す動作に似ているというように、現実世界の動作と照らし合わせてみることは「直感的」な使用感につながるデザインを選定するヒントになりそうだと感じた Kotlin Multiplatformで SaaS 大規模アプリの生産性を向上させる技術的意思決定と導入効果を最大化するための取り組み fortee.jp 概要 Kotlin Multiplatform(以降KMP)導入までの意思決定と導入する際の取り組みを紹介 感想 私自身が Android アプリエンジニアのためKMPを学習する際ハードルとして意識していなかった Android ではお馴染みのGradleなどのツールやライブラリやKotlin学習などを iOS エンジニアがしっかりキャッチアップできるような取り組みがなされているのが印象的だった 学習コスト以外では、 Objective-C 変換される点はSwift変換がロードマップ上にはあるそうなので、解消されることを期待 ここで紹介した以外にも、本当に興味が惹かれるセッションばかりで、技術的モチベーションの刺激にもなりました。 登壇メンバーも終わった後の解放感がすごかったと言っていたので、登壇者の方々は当日まで入念に準備を重ね、重責に耐えて挑まれたものと思います。 登壇者の皆様、本当にお疲れ様でした&ありがとうございました! さいごに 以上、3日間に渡る「iOSDC Japan 2024」の模様をお伝えしましたがいかがだったでしょうか。 iOSDC自体はこれまでも断片的には楽しませていただいていましたが、今年度はメンバーも登壇し初の現地参加ということでまた特別な体験でした。 リモートでは得られない現地の熱気や交流を通じて、チームとしてもお互いに更に理解を深めたり、 トーク セッションを受けて早くも創作意欲が湧き上がったりと有意義な経験を得る事ができました。 そして最後にはなりますが運営いただいたスタッフの皆様、登壇者の皆様、参加者の皆様、本当にお疲れ様でした。 チームでの集合写真
アバター
はじめに 復習:PGlite pg-gateway pg-gatewayとPGliteを起動してSQLクライアントから接続する まとめ はじめに こんにちは、エンジニア2年目のTKDSです! 前回 はPGliteの概要・使い方・速度実験について記事にしました。 今回はさらに、PGliteへの SQL クライアントからの接続を可能とするpg- gateway について紹介し、活用例について示します。 復習:PGlite PGliteは、 PostgreSQL をWebAssembly(WASM)に コンパイル した軽量なデータベースエンジンです。 これにより、ブラウザ、Node.js、Bun、DenoなどでPostgresの機能を利用でき、開発者はローカルやサーバーレス環境でデータベース操作を行うことが可能です。 PGliteは、インメモリデータベースや ファイルシステム (Node.jsやBun)、IndexedDB(ブラウザ)での永続化をサポートします。 pg- gateway TypeScript library that implements the Postgres wire protocol from the server-side. It provides APIs you can hook into to handle authentication requests, queries, and other client messages yourself. 翻訳:サーバーサイドでPostgresのワイヤー プロトコル を実装するTypeScriptライブラリです。このライブラリは、認証リク エス ト、クエリ、およびその他のクライアントメッセージを自分で処理するための API を提供します。 簡単にいうとこのライブラリは、データベースとやりとりするための仕組みをサーバー側で実現するものです。 これによって、簡単にPGliteへ外部のクライアントから接続できるようにしてくれます。 pg- gateway とPGliteを起動して SQL クライアントから接続する まずはpg- gateway を使えるようにします。 # クローンする git clone https://github.com/supabase-community/pg-gateway.git # ビルドの設定があるディレクトリに移動 cd pg-gateway/packages/pg-gateway/ # 必要な依存関係のインストール npm install # ビルド npm run build # PGlite+pg-gateway用のディレクトリを作る # 元いたディレクトリに戻る cd - # ディレクトリの作成 mkdir -p pglite-with-gateway/lib cd pglite-with-gateway/lib # ビルド成果物のコピー cp ../../pg-gateway/packages/pg-gateway/dist/index.js ./ cp ../../pg-gateway/packages/pg-gateway/dist/index.mjs ./ cp ../../pg-gateway/packages/pg-gateway/dist/index.d.ts ./ # プロジェクトルートで初期化 npm init 生成されたpackage. json の中身を以下のように書き換えてください。 { " name ": " pglite-with-gateway ", " version ": " 1.0.0 ", " description ": " A project integrating PGlite with pg-gateway ", " main ": " src/app.js ", " directories ": { " lib ": " lib " } , " scripts ": { " start ": " node src/app.js " } , " author ": "", " license ": "", " dependencies ": { " pg-gateway ": " file:./lib/index.js " , } , " type ": " module " } PGliteのインストール npm install @electric-sql/pglite # dotenvのインストール npm install dotenv # pg-protocolのインストール npm install pg-protocol 準備が整ったので、コードを準備して起動していきます。 pg-gatewayのREADME を参考にコードを書きます。 "use strict" ; import net from "node:net" ; import dotenv from "dotenv" ; import { PGlite } from "@electric-sql/pglite" ; import { PostgresConnection } from "../lib/index.mjs" ; // 環境変数読み込み dotenv . config () ; // PGliteのインスタンス作成 const pg = new PGlite () ; // 平文パスワードでの認証処理 async function validateUserCredentials ( credentials ) { const { user , password } = credentials ; const validUser = process . env . DB_USER ; const validPassword = process . env . DB_PASSWORD ; // ユーザー名とパスワードが一致するか確認 return user === validUser && password === validPassword ; } // クライアントメッセージの処理 async function handleClientMessage ( data , isAuthenticated , connection ) { if ( ! isAuthenticated ) { return false ; } try { const [[ _ , responseData ]] = await db . execProtocol ( data ) ; connection . sendData ( responseData ) ; } catch ( err ) { console . error ( "Error processing message:" , err ) ; connection . sendError ( err ) ; connection . sendReadyForQuery () ; } return true ; } // クライアント接続処理 function handleClientConnection ( socket ) { const connection = new PostgresConnection ( socket , { serverVersion : "16.3 (PGlite 0.2.0)" , authMode : "cleartextPassword" , // 平文パスワード認証 validateCredentials : validateUserCredentials , onStartup : async () => { await db . waitReady ; return false ; } , onMessage : ( data , { isAuthenticated }) => handleClientMessage ( data , isAuthenticated , connection ) , }) ; socket . on ( "end" , () => { console . log ( "Client disconnected" ) ; }) ; socket . on ( "error" , ( err ) => { console . error ( "Socket error:" , err ) ; }) ; } // サーバーの起動 function startServer () { const server = net . createServer ( handleClientConnection ) ; server . listen ( 5432 , () => { console . log ( "Server listening on port 5432" ) ; }) ; server . on ( "error" , ( err ) => { console . error ( "Server error:" , err ) ; }) ; } // サーバーを開始 startServer () ; pg-protocol関連でインポートできないエラーがでる場合があります。 エラーメッセージを確認し、node_modules内のファイルを書き換えてください。 作業が完了したら起動します。 npm start 別のターミナルを開いて接続します。 # psqlがない場合はインストールする sudo apt install -y postgresql-client # 接続 psql -h localhost -U postgres 以下のように繋がります。 これで、 SQL クライアントからPGliteにアクセスすることが可能になりました! まとめ pg- gateway を動かすまでについて解説しました。 情報が少なく、動かせるようになるまで苦労しました。 現時点で実用するには少し厳しいかなと感じました。これからに期待ですね! (実はpg- gateway を使ってGoからクエリ実行しようとしてできず、諦めました...。ログインができるのですがpg- gateway 側で送信されたクエリを実行できず?) ここまで読んでいただきありがとうございました!
アバター
はじめに 対象読者 TL;DR OpenAPI Specificationとは OASを導入することの何が嬉しい? 1. プロダクトごとにAPI仕様書を記述するツールやフォーマットがバラバラでスイッチングコストがかかる 2. 記述量が増えると動作が重くなる 3. API仕様変更の伝達漏れの多発 導入までの課題 1. OASの調査に時間をかけすぎた 2. OASのデメリット全てに対応策を講じようとしてしまったこと 導入して1年、開発環境は改善されたのか? おわりに はじめに ラク スフロントエンド開発2課の斉藤です。 ラク スの開発するプロダクトである楽楽明細、楽楽電子保存、楽楽請求では OpenAPI Specification (以下 OAS )を採用した開発を行っています。 今でこそ OAS を活用した開発を行うことができていますが、導入にあたっては様々な苦労がありました。 そこで今回は 何故 OAS を導入したのか 導入にあたってどのような課題があったのか 導入して実際に効果はあったのか を紹介したいと思います。 対象読者 OAS の導入を検討している人 OAS の導入に周りから賛同を得られない人 OAS 導入の効果が知りたい人 TL;DR 時間がない方に向けて結論から書きます。 従来の API 仕様書の閲覧パフォーマンスやコミュニケーションの齟齬による課題を解決したくて OAS を導入した。 導入にあたっては ステークホルダー の不安を ヒアリ ングし、ケアをすることで合意を得る事ができた。 OAS 導入後、開発者の満足度は高く、 工数 削減の効果があった。またAIと組み合わせる事で生産性がさらに向上する副次効果もあった。 OpenAPI Specificationとは OAS とはRESTful API を定義するための標準仕様であり、もともとはSwaggerと呼ばれていました。 *1 JSON または YAML 形式で記述され、 API のエンドポイント、HTTPメソッド、パラメータ、レスポンス、エラーハンドリング、などを定義することができます。 例えば以下は YAML 形式で記述された OAS の例です。 openapi : 3.0.2 servers : - url : /v3 info : description : |- This is a sample Pet Store Server based on the OpenAPI 3.0 specification. tags : - name : pet description : Everything about your Pets externalDocs : description : Find out more url : 'http://swagger.io' paths : /pet : post : tags : - pet summary : Add a new pet to the store description : Add a new pet to the store operationId : addPet responses : '200' : description : Successful operation content : application/json : schema : $ref : '#/components/schemas/Pet' '405' : description : Invalid input requestBody : description : Create a new pet in the store required : true content : application/json : schema : $ref : '#/components/schemas/Pet' これをSwagger UIのようなツールを用いて表示すると、以下のようにシンプルなUIで API 仕様を確認することができます。 公式がサンプルを用意 しているので、こちらを参照するとより具体的な使用イメージが掴めると思います。 OAS を導入することの何が嬉しい? OAS を導入する前、プロダクト開発チームは API 仕様書について以下の課題を抱えていました。 1. プロダクトごとに API 仕様書を記述するツールやフォーマットがバラバラでスイッチングコストがかかる 例えばあるプロダクトでは API 仕様書の記述に スプレッドシート 、他のプロダクトでは Google Docs 、といったようにそれぞれが異なるツールを用いていました。 記述のフォーマットも統一されておらず、複数のプロダクトを横断的に開発するチームにとっては記述ルールの学習コストが無視できないものになっていました。 2. 記述量が増えると動作が重くなる これは Google Docs を採用しているプロダクトで顕著だったのですが、 API のエンドポイントが増えるにつれ動作がカクカクしてしまい、閲覧するにも一苦労という状況が生まれていました。 これに対してはドキュメントを分割するなどの対策が取れますが、複数ファイルを参照しながら開発するのは良い体験とは言えませんでした。 API 仕様は何度も繰り返し参照するドキュメントなので、閲覧時のパフォーマンスは早急に改善したいポイントでした。 3. API 仕様変更の伝達漏れの多発 開発する中で API 仕様の変更はつきものです。(...ですよね?) 大きな変更は滅多にありませんが、軽微な変更、例えばプロパティ名をより適切な 命名 に変更したり、エラーパターンを追加したりといったことはあります。 そういった変更の共有漏れが頻発し、疎通テストで初めて発覚して慌てて修正するといった状況が多くありました。 コードの修正は開発工程の初期であるほど低コストで済みます。 修正が起きた都度、チーム内で変更が共有されている状況を作る方法を模索するも最適解が出ない状態でした。 これらの課題を全て解決したいと考えたとき、 OAS が選択肢として挙がりました。 OAS を用いると 仕様の記述フォーマットが規定されているため、チーム内で共通言語を用いた横断的な開発ができる Swagger UIのようなツールを用いれば多量の API 仕様を1つのHTMLで高いパフォーマンスで閲覧できる OAS からI/Fの型を自動生成することで型レベルで伝達漏れを防ぐことができる といったメリットがあり、自分たちの抱える課題を一挙に解決するできるのでは?という期待から、導入検討に進むことになりました。 導入までの課題 OAS を使えば課題解決できるヤッター導入しま〜す!あとよろしく、で通ったら苦労しません。 私たちはチームで仕事をしているので、 ステークホルダー と合意形成をする必要があります。 また、弊社が規定する ラクスリーダーシッププリンシプル という行動指針に 全体最適 視点を持つ というものがあります。 この指針に照らし合わせ、 OAS 導入が 全体最適 に寄与するという仮説をチームから納得してもらう必要がありました。 そこで各々のプロダクトを担当するバックエンドエンジニアと会議を行い、 OAS の概要と導入を検討していることを伝えました。 中にはぜひ導入したいというエンジニアもいれば、いきなり変えるのには不安がある、といった意見もありました。 さらに深掘って、導入にあたっての疑問点や不安に思っていることを ヒアリ ングすると以下の意見が挙がりました。 OAS 導入のメリットは理解できたが、開発フローがどのように変わるかイメージできない OAS 導入によって自分が行うタスクがどう変わるのかイメージしづらい OAS はフォーマットが規定されているため、学習コストが気になる そこで1, 2に関しては OAS 導入の前後で変わることをスライドを用いて説明することでイメージを掴んで頂きました。 また3に関しては勉強会を開催すること、 スプレッドシート で書かれた既存の API を OAS に書き換え、記入例を示すことで対応しました。 その甲斐あってか最終的には導入を提案した3つのプロダクト全てにおいて、合意を得ることができました。 合意形成がうまくいったポイントとしては 相手が不安に思っていることを ヒアリ ングし、その不安は杞憂である、もしくは対応策があることを根拠を持って答えることができた点 かと思っています。 と、さらっとスマートに事が運んだかのように書いていますが、 最終的に合意形成に至るまでに3ヶ月くらいかかっています。 理由としては OAS の調査に時間をかけすぎたこと OAS のデメリット全てに対応策を講じようとしてしまったこと が挙げられます。 1. OAS の調査に時間をかけすぎた OAS の調査にあたり公式ドキュメントを読み込んでいたのですが、覚えるべき事が膨大でOpenAPIを書けるようになるまでにはかなりの時間がかかるのでは?と考えるようになっていきました。 フロントエンドエンジニアだけで完結するならまだ良かったのですが、いずれはバックエンドチームにもOpenAPIを書いてもらうようにしたかったので、学習コストを理由に導入を断られてしまう不安がありました。 そこで Stoplight Studio や Apicurio Studio といった GUI でOpenAPIを記述できるようなサービスを使えば学習コストを抑えられそうと思い至り、さらにそちらの調査にも時間を割いてしまいました。 結論から書くと、現在これらのツールは使用していません。 OAS を導入した今言えることは、そもそもOpenAPIの学習コストは高く無いということです。 OpenAPIは様々な API 仕様記述のフォーマットを用意していますが、使用するのはその中の一部であり、公式が用意しているドキュメントを真似ればすぐに書けるようになります。 また弊社では Github Copilotを全社的に導入しており、Copilotは OAS の推論がとても得意なので、知識が浅いうちでも強力なサポートを得る事ができます。 したがって、学習コストを下げるために GUI ツールを導入するというのはコストと効果が見合っていないと判断しました。 実際、バックエンドに対して不安を ヒアリ ングしたときに学習コストの懸念は挙がったのですが、先述したようにちょっとした勉強会の開催と記入例の提示で納得していただけました。 ドキュメントを読んだ印象だけで学習コストが高いと決めつけ、あれもこれもと調査に時間を使ったのはもったいなかったです。 2. OAS のデメリット全てに対応策を講じようとしてしまったこと OAS を調査していく中で スプレッドシート や Google Docs にはできてOpenAPIにはできないことがいくつかある事がわかりました。 例えば スプレッドシート や Google Docs はドキュメント同士をリンクすることができたり、記述した内容に対するコメント等ができますが、OpenAPIではできません。 そこで、OpenAPIの description をうまく活用する事でどうにかデメリットを吸収できないかと思索していました。 結局今は description の記述ルールなどは特に設けずに運用しています。 ドキュメント同士のリンクなどはできれば便利ですが、必須な機能ではありません。 これを無理やり実現しようとして運用コストが高くなっては本末転倒です。 新しい手法を導入する事でメリットとデメリットの両方が生じるのは当然です。 生じるデメリットが本来解決したかった課題の大きな障害となるかどうかという視点で、対応の要否を最初から取捨選択しておくべきでした。 実際このようなデメリットが存在することを伝えつつ OAS 導入をチームに提案しましたが、すんなり受け入れてもらえました。 振り返ると、2つの失敗の共通点は 思い込み だったと思います。 学習コストが高いのではないか? デメリットに対する完璧な対応策を考えておくべきではないか? これらに対処しなければ合意をもらえないのではないか? このような思い込みを根拠にした意思決定が、多くの時間をかけてしまった原因だったように思います。 次に同じような課題に直面した際は ある程度調査したら実際に手を動かしてシミュレーションしてみる 早い段階でチームに相談しデメリットが許容できるものか認識を擦り合わせておく ことで思い込みによる無駄を避けるように行動していきたいと思います。 導入して1年、開発環境は改善されたのか? OAS を導入してから約1年経った現在(2024/08)は以下の流れで開発を行っています。 フロントエンドエンジニアがOpenAPIで API 要求仕様を記述しプルリク エス トを出す バックエンドエンジニアが API 要求仕様のレビューを行い、 API 仕様を確定させる OpenAPIから型やコードを自動生成する(フロントエンドは openapi-generator を使用) 生成した型をパッケージ化しプライベート レジストリ にpublish npm installで生成した型をインストールしI/Fを実装 フロントエンドもバックエンドもOpenAPIから自動生成した型やコードを使用しているので、疎通テストのバグが大幅に減少し 工数 削減となりました。 また自動生成した型と Github Copilotを組み合わせて、モックデータを推論できるという副次効果の恩恵にもあずかっています。 もちろん当初挙げていた課題も解決する事ができ、開発体験も改善されました。 さらに今回エンジニアに向けて OAS を導入して実際にどう感じているか、アンケートを取ってみたので結果を紹介したいと思います。 回答者の属性: OAS 導入後、OpenAPIを参照もしくは記述したことがあるエンジニア 有効回答数:9件 Q: OpenAPIを使った開発において、改善が必要だと感じた点や課題を教えてください。 A: 実装過程の後半でSwaggerの修正に少しハードルを感じていますので、FE/BE共に修正が必要なら早急に相談し、すぐ修正するコミュニケーションや雰囲気をお互いで作っていきたいと思っています。 Q: その他ご意見ご感想などあれば記述してください。 A: 導入当時、OpenAPIを導入したい経緯や課題は理解できたが、既存の 開発プロセス のどこで何をすればよいのかはよくわからなかった。今でも正しく理解できているか微妙。 全体的に高い満足度であり、少なくとも定性的には OAS 導入の効果はあったと言えそうです。 ただ、 OAS の導入プロセスについては不満と回答した方はいないものの、他の項目と比べると満足度が低めです。 自由記述の回答にもある通り、「 開発プロセス のどこで何をすればよいのかはよくわからなかった。」と意見を頂いており、スライドによる説明だけでは伝わりづらかった部分があったと考えられます。 小さくプロトタイプの リポジトリ を作って、 OAS 導入後の 開発プロセス のシミュレーションを行うなどすればより理解して貰いやすかったのかなと思います。 おわりに 本記事では OAS 導入に至った経緯から導入までの課題、その後の効果まで紹介しました。 導入までには数々の障害があり、至らない部分も多くありましたがなんとか開発フローに組み込む事ができました。 全体としては高い満足度となり、当初の課題も解決できたため導入してよかったと感じています。 今後さらなる 開発プロセス の改善に取り組む際には、今回の反省点を活かし、より効率的に、より多くの ステークホルダー に納得していただけるよう進めていきたいです。 *1 : 曖昧な情報です。おそらくOpenAPI2系まではSwagger, 3系からは OAS と呼ばれています。
アバター
はじめに PGliteの概要 PGliteの特徴 PGliteを試す ブラウザで使う PGliteの速度計測 まとめ はじめに こんにちは!エンジニア2年目のTKDSです! 今回はPGliteについて調べてみました! 概要・使い方・速度実験・まとめの内容で記事は構成されています。 使ってみた結果として、軽量高速であり色々使いみちがありそうなツールだと感じました。 ぜひ最後まで読んでいただけると幸いです。 PGliteの概要 PGliteは、 PostgreSQL をWebAssembly(WASM)に コンパイル した軽量なデータベースエンジンです。 これにより、ブラウザ、Node.js、Bun、Denoなどで PostgreSQL の機能を利用でき、開発者はローカルやサーバーレス環境でデータベース操作を行うことが可能です。 PGliteは、インメモリデータベースや ファイルシステム (Node.jsやBun)、IndexedDB(ブラウザ)での永続化をサポートします。 PGliteの特徴 公式サイト によると、 1. Lightweight 2. Extendable 3. Reactive 上記、3つの特徴が挙げられていました。 1:PGliteのWASMバイナリが圧縮状態で3MB程度であること 2: PostgreSQL の 拡張機能 が適用可能であること 3:に関してはテーブルが変更されたときに更新された結果を受け取る機能をサポートしていること から来ているそうです。 3はCDC(Change Data Capture)の機能に似てますね! フロントエンドは詳しくないのですが、状態管理などにも使えるのでは?など思い浮かびました。 PGliteを試す ドキュメントをみつつ環境構築してみましょう。 手軽に試したい場合は、 こちらのリンク から試すこともできます。 今回は手元で試してみます。 npm install @electric-sql/pglite application.jsに下記の内容を書き込みます。 const { PGlite } = require ( '@electric-sql/pglite' ) ; ( async () => { try { const db = new PGlite () ; await db . exec ( ` CREATE TABLE IF NOT EXISTS todo ( id SERIAL PRIMARY KEY, task TEXT, done BOOLEAN DEFAULT false ); INSERT INTO todo (task, done) VALUES ('Install PGlite from NPM', true); INSERT INTO todo (task, done) VALUES ('Load PGlite', true); INSERT INTO todo (task, done) VALUES ('Create a table', true); INSERT INTO todo (task) VALUES ('Update a task'); ` ) ; const ret = await db . query ( ` SELECT * from todo WHERE id = 1; ` ) ; console . log ( "Query Result:" , ret . rows ) ; } catch ( error ) { console . error ( "Error executing query:" , error ) ; } })() ; ドキュメントの内容をそのままコピーしても動かないので、少々修正してあります。 結果は以下のとおりです。 無事に動かすことができました。 雑に時間を測ってみると起動から SQL 実行まで2.08秒ほどで完了しています。非常に高速ですね! ブラウザで使う コマンドライン で決まった SQL を実行する以外にも、ブラウザでREPLを使って、対話的にPGliteにアクセスできます。 ドキュメントに コード が記載されていますが、2024/8/18時点では、そのまま使用できません。 開発者ツールでみると、 Failed to load resource: the server responded with a status of 404 () とメッセージが表示されています。 ソースからファイルを開くと Couldn't find the requested file /dist-webcomponent/Repl.js in @electric-sql/pglite. と表示されています。 おそらくドキュメントのコードのリンクが間違っていそうです。 JSDELIVER で調べてみましょう。 調べてみると、下記画像のようにpglite-replがありました!このパスに変更すればいけそうです。 念のため中身をチェックしてから使用しました。 では、以下のコードをファイルに書き、ブラウザで開いてください。 <!doctype html> < html lang = "ja" > < head > < meta charset = "UTF-8" /> < meta name = "viewport" content = "width=device-width, initial-scale=1.0" /> < title > PGlite REPL Example </ title > < script src = "https://cdn.jsdelivr.net/npm/@electric-sql/pglite-repl@0.2.1/dist-webcomponent/Repl.js" type = "module" ></ script > </ head > < body > < h1 > PGlite REPL </ h1 > <!-- PGlite REPLコンポーネントがここに表示されます --> < pglite-repl id = "repl" ></ pglite-repl > < script type = "module" > import { PGlite } from "https://cdn.jsdelivr.net/npm/@electric-sql/pglite/dist/index.js" ; // PGliteインスタンスを作成 const pg = new PGlite () ; // REPL要素を取得 const repl = document . getElementById ( "repl" ) ; // PGliteインスタンスをREPLに設定 repl . pg = pg ; </ script > </ body > </ html > REPLを開くことができ入力もできました! PGliteの速度計測 次にPGliteの速度を測ってみます。 SELECT、 INSERT、UPDATE、DELETEについて、それぞれ実験します。 以下のコードで実験します。 各DB操作を行い、1000, 2000, 3000, 4000, 5000, 10000と扱う件数が増えていきます。 import { PGlite } from "@electric-sql/pglite" ; import { performance } from "perf_hooks" ; const measureDbStartup = () => { const dbStartTime = performance . now () ; // DB起動時間の測定開始 const db = new PGlite () ; // データベースインスタンスを初期化 const dbEndTime = performance . now () ; // DB起動時間の測定終了 const dbStartupTime = dbEndTime - dbStartTime ; console . log ( `DB startup time: ${ dbStartupTime . toFixed ( 3 )} ms` ) ; return db ; } ; const initDb = async ( db , numRows ) => { await db . exec ( ` CREATE TABLE IF NOT EXISTS test_table ( id SERIAL PRIMARY KEY, name TEXT, value INTEGER ); ` ) ; const values = [] ; for ( let i = 0 ; i < numRows ; i ++ ) { values . push ( `('name_ ${ i } ', ${ i } )` ) ; } await db . exec ( `INSERT INTO test_table(name, value) VALUES ${ values . join ( ", " )} ` , ) ; } ; const measureOperationTime = async ( operation , db , numRows ) => { let totalTime = 0 ; for ( let trial = 1 ; trial <= 3 ; trial ++ ) { const startTime = performance . now () ; await operation ( db , numRows ) ; const endTime = performance . now () ; const duration = endTime - startTime ; totalTime += duration ; console . log ( `Trial ${ trial } , ${ operation . name . toUpperCase ()} ${ numRows } rows: ${ duration . toFixed ( 3 )} ms` , ) ; } const averageTime = totalTime / 3 ; console . log ( `Average ${ operation . name . toUpperCase ()} time for ${ numRows } rows: ${ averageTime . toFixed ( 3 )} ms` , ) ; console . log ( `Time per row: ${( averageTime / numRows ) . toFixed ( 6 )} ms/row` ) ; } ; const selectOperation = async ( db , numRows ) => { await db . query ( `SELECT * FROM test_table LIMIT ${ numRows } ` ) ; } ; const insertOperation = async ( db , numRows ) => { const values = [] ; for ( let i = numRows ; i < numRows * 2 ; i ++ ) { values . push ( `('name_ ${ i } ', ${ i } )` ) ; } await db . exec ( `INSERT INTO test_table(name, value) VALUES ${ values . join ( ", " )} ` , ) ; } ; const updateOperation = async ( db , numRows ) => { await db . exec ( `UPDATE test_table SET value = value + 1 WHERE id <= ${ numRows } ` , ) ; } ; const deleteOperation = async ( db , numRows ) => { await db . exec ( `DELETE FROM test_table WHERE id <= ${ numRows } ` ) ; } ; // 実行 const main = async () => { const operationCounts = [ 1000 , 2000 , 3000 , 4000 , 5000 , 10000 ] ; const operations = [ selectOperation , insertOperation , updateOperation , deleteOperation , ] ; for ( const count of operationCounts ) { for ( const operation of operations ) { console . log ( `\nRunning ${ operation . name . toUpperCase ()} test with ${ count } rows:` , ) ; const db = measureDbStartup () ; // DB起動時間の測定とインスタンス作成 await initDb ( db , count ) ; // DB初期化とデータ挿入 await measureOperationTime ( operation , db , count ) ; // 操作のパフォーマンス測定 } } } ; main () . then (() => console . log ( "All tests completed" )) . catch (( err ) => console . error ( "Error:" , err )) ; 結果を以下にまとめます。 行数 平均起動時間 (ms) SELECT (ms) INSERT (ms) UPDATE (ms) DELETE (ms) SELECT (ms/row) INSERT (ms/row) UPDATE (ms/row) DELETE (ms/row) 1000 0.141 2.539 3.651 4.893 0.476 0.002539 0.003651 0.004893 0.000476 2000 0.051 2.801 7.267 9.216 0.701 0.001401 0.003633 0.004608 0.000350 3000 0.071 3.867 10.362 13.177 0.835 0.001289 0.003454 0.004392 0.000278 4000 0.035 5.588 14.742 17.931 1.776 0.001397 0.003685 0.004483 0.000444 5000 0.047 7.007 19.127 23.373 2.102 0.001401 0.003825 0.004675 0.000420 10000 0.036 10.971 37.880 43.966 3.535 0.001097 0.003788 0.004397 0.000354 起動時間は概ね1msかからず、高速であることがわかります。 データ操作も高速です。 1万件でも一番遅くて、UPDATEの43msのため、テスト用途などであれば十分実用に耐えるのではないかと感じました。 まとめ 今回はPGliteを動かすまでの方法と試行錯誤について書きました。 まだ開発中ということもあり、色々不正確なことや情報がなく大変でした。 PGlite自体は非常に高速でREPLも用意されており、ツールとして非常に魅力的でした! 今回は非常に簡単な使い方だけだったので、今後は起動状態を維持し、クライアントライブラリから接続して使ってみたり、テストでのDBとして使ってみたいと考えています。 ここまで読んでいただきありがとうございました!
アバター
はじめに 変数のシャドーイングとは? エラーハンドリングの例 シャドーイングとエラーハンドリングの例 問題点と対策 まとめ 年に1度の技術イベント「RAKUS Tech Conference」を開催します!! はじめに エンジニア2年目のTKDSです! 今回は変数の シャドーイング について調べました。 Goを用いて、 シャドーイング に関する例を2つほど示します。   変数の シャドーイング とは? シャドーイング は、内部スコープで宣言された変数が外部スコープの同名変数を内部スコープ内では上書きしてしまうことです。 サンプルコードを以下に示します。 Go Python JavaScript いずれの言語でも変数が再宣言されて上書きされていることがわかります。 今回は、Goについて扱っていきます。 シャドーイング が関わるケースの一例として、エラーハンドリングの例を示します。 エラーハンドリングの例 Goのエラーハンドリングを題材に シャドーイング について、実際に試してみます。 Goではerrorのログ出力などをdeferを使って最後にまとめることができます。 エラー時のログ出力を個別にするケース https://go.dev/play/p/aVNJ81TxWY- package main import ( "fmt" "log/slog" ) func main() { err := example() fmt.Println(err) } func example() error { cfg1, err := dummyFunc( "" ) fmt.Println( "first: " , cfg1) if err != nil { slog.Info( "in block" ) return err } cfg2, err := dummyFunc( "" ) fmt.Println( "Second: " , cfg2) if err != nil { slog.Info( "in block" ) return err } cfg3, err := dummyFunc( "error" ) fmt.Println( "third: " , cfg3) if err != nil { slog.Info( "in block" ) return err } return nil } func dummyFunc(message string ) ( string , error ) { if message == "" { return "no message" , nil } return "dummy" , fmt.Errorf(message) } エラー時のログ出力をまとめて行うケース https://go.dev/play/p/T8guyspQDBU package main import ( "fmt" "log/slog" ) func main() { err := example() fmt.Println(err) } func example() (err error ) { defer func () { if err != nil { slog.Info( "in block" ) } }() cfg1, err := dummyFunc( "" ) fmt.Println( "first: " , cfg1) if err != nil { return err } cfg2, err := dummyFunc( "" ) fmt.Println( "Second: " , cfg2) if err != nil { return err } cfg3, err := dummyFunc( "error" ) fmt.Println( "third: " , cfg3) if err != nil { return err } return nil } func dummyFunc(message string ) ( string , error ) { if message == "" { return "no message" , nil } return "dummy" , fmt.Errorf(message) } シャドーイング とエラーハンドリングの例 では、 シャドーイング がどのように関わってくるのか、下記に示します。 例1) シャドーイング が起こっても大丈夫なケース https://go.dev/play/p/u-X4E2BzV1- package main import "fmt" func main() { err := example() fmt.Println(err) } func example() (err error ) { defer func () { fmt.Printf( "defer block:%s \n " , err) }() fmt.Println(err) cfg, err := dummyFunc( "block 1 error" ) if err != nil { return err } fmt.Println(cfg) return nil } func dummyFunc(message string ) ( string , error ) { if message == "" { return "no message" , nil } return "dummy" , fmt.Errorf(message) } cfg, err := dummyFunc("block 1 error") でerrが上書きされています。 再度上書きされることはなくreturnされるため、想定通り、 block 1 error が出力されます。 例2 ) シャドーイング で挙動がおかしくなるケース https://go.dev/play/p/-8aV2X6An3u package main import "fmt" func main() { err := example() fmt.Println(err) } func example() (err error ) { defer func () { fmt.Printf( "defer block:%s \n " , err) }() fmt.Println(err) cfg, err := dummyFunc( "block 1 error" ) if err != nil { cfg, err := dummyFunc( "シャドーイング" ) fmt.Println(cfg) if err != nil { return err } return nil } fmt.Println(cfg) return nil } func dummyFunc(message string ) ( string , error ) { if message == "" { return "no message" , nil } return "dummy" , fmt.Errorf(message) } cfg, err := dummyFunc("block 1 error") とifブロック内でerrを上書きされています。 最外部で変数に代入されたエラーである block 1 error が上書きされてしまいます。 問題点と対策 例2では、例1で返せていたエラーが返せなくなります。 具体的には、exampleの最外部で取得したエラーが返されなくなります。 cfg, err := dummyFunc("block 1 error") で返ってきたエラーが、18行目からのif文の中で シャドーイング されたままリターンされています。 上書き対策としては名前付き変数をブロック内で重複しにくい名前にするなどが考えられます。 これにより、上書きリスクを減らせます。 乱用するとプログラムがわかりにくくなるリスクがありますが、errorなどは毎回別の名前を使うのは大変なので、うまく活用すればプログラムを簡潔に保てるテクニックです。 まとめ 今回は変数の シャドーイング について調べました。 またGoのエラーハンドリング時に踏みそうな間違いのケースを示しました。 同名の変数をスコープ内で上書きするケースが多いのは、エラーハンドリングで定型文が多いGoで起きやすいミスかもしれないので気をつけたいと思いました。 ここまで読んでいただき、ありがとうございました! 年に1度の技術イベント「RAKUS Tech Conference」を開催します!! 今年も ラク ス開発本部主催の技術カンファレンス、「RAKUS Tech Conference 2024」を開催します! 「RAKUS Tech Conference」は、 SaaS 開発における取り組みや知見を紹介する、 ラク ス開発本部主催の技術カンファレンスです。 ラク ス開発本部のミッションに込めた想いをエンジニア/デザイナーが生の声でお届けします。 皆さまのご参加、お待ちしております! techcon.rakus.co.jp
アバター
こんにちは! メールディーラー開発課のymyhero7です。 先日、弊社の勉強会で「不吉コードの大掃除」というテーマで発表をしました。 そこで話した、レガシーな社内向け機能を改修したエピソードをご紹介します! 改修することになった経緯 既存コードの問題点 改修の方法 成果 まとめ 年に1度の技術イベント「RAKUS Tech Conference」を開催します!! 改修することになった経緯 メールディーラーの社内向け機能では、メールディーラーを使用されるお客様のアカウント設定やメー ルボックス 開設などの事務作業を行うことができます。 この事務作業を、従来は、メールディーラーの社内向け機能と販売管理システムの両方で重複管理していました。 そのため、データの不一致や作業コストが発生してしまっていました。 この問題を解決するため、販売管理システムに登録した情報を API を介して自動的にメールディーラーに反映できるように社内向け機能を改修することにしました。 改修の ビフォーアフター 既存コードの問題点 改修のため既存コードを確認してみると問題点がたくさんありました! ビューロジックと ビジネスロジック が混在している ビューロジックと ビジネスロジック が適切に分離されておらず、1つのファイルに混在して書かれていました 共通関数が1つのファイルに大量に書かれている 共通関数群が書かれた約7000行の巨大ファイルが存在していました 1つの関数が複数の役割を持っている 例えば、バリデーションとデータ整形の両方を行っている関数がありました 既存コードに困惑している図 このような問題から、可読性が低く、自動テストの作成も困難な状態でした。 そのため、既存コードを使い回すのではなく、思い切って社内向け機能を作り直すことにしました! 改修の方法 以下の手順で改修を行いました。 ユースケース と必要な処理の整理 既存コードから、 ユースケース ごとに必要な処理を洗い出し、実装するべき処理を明確にしました。 Laravelを活用し、 ADR パターンで実装 既存コードはノン フレームワーク でしたが、今回はlaravelを使用して ADR パターンで実装しました。 ADR パターン Laravelと ADR パターンは、UI刷新の際に使用しているので、その時の経験を活かすことができました。 UI刷新について、詳しくは以下をご覧ください。 fortee.jp 成果 今回の改修により、次のような成果を上げることができました! 可読性の向上 ファイルや関数が適切な単位に分割されたため、可読性が向上しました 自動テストの実施 全ての処理で自動テストを行うことができるようになりました 開発スピードの向上 Laravelの使用と自動テストにより、スピード感を持って開発を進めることができました まとめ レガシーな社内向け機能を改修したエピソードをご紹介しました。 開発に携わったメンバーからは、 「既存処理を使い回さず、勇気を持って作り直してよかった」 「社内向けシステムであっても保守性を考えることは大切だ」 という感想が挙がっていました! 今後も、このような生産性向上を意識した開発を心掛けていきたいと思います。 年に1度の技術イベント「RAKUS Tech Conference」を開催します!! 今年も ラク ス開発本部主催の技術カンファレンス、「RAKUS Tech Conference 2024」を開催します! 「RAKUS Tech Conference」は、 SaaS 開発における取り組みや知見を紹介する、 ラク ス開発本部主催の技術カンファレンスです。 ラク ス開発本部のミッションに込めた想いをエンジニア/デザイナーが生の声でお届けします。 皆さまのご参加、お待ちしております! techcon.rakus.co.jp
アバター
SRE課の飯野です。 去る2024/7/9(火)、『 Platform Engineering Kaigi 2024 』(以下PEK)が開催されました。 弊社からは7名(SRE課6名+インフラ部長)が現地参加し、登壇企業の皆さまの熱量あふれるセッションを肌で体感してきました。 本ブログでは、PEK参加後にSRE課メンバーで実施した社内でのふりかえりの内容をお届けします。 目次 PEKとは? 当日の様子 ふりかえりやってみよう 総括 PEKとは? 『Platform Engineering Kaigi 2024』は、プラットフォームエンジニアリングをテーマにしたテックカンファレンスです。 もともと『 Platform Engineering Meetup 』という勉強会を主催していたコミュニティが「 一般社団法人クラウドネイティブイノベーターズ協会 」という団体を立ち上げ、その団体が今回日本で初めとなる大型カンファレンスを開催する運びとなりました。 オフライン会場は東京・お台場の「 docomo R&D OPENLAB ODAIBA」にて行われ、オンライン配信も含むハイブリッド方式で開催されました。 記念すべき第一回のコンセプトは「 DevOpsの荒波を乗りこえる、エンジニアの 羅針盤 」。 Platform Engineering Kaigiは、現在注目を浴びているPlatform Engineeringをテーマにしたテク ノロ ジー カンファレンスです。 コンテナをはじめとした クラウド ネイティブ技術の発展やDevOpsの浸透、さまざまな便利なツールの登場により、アプリケーション開発の現場は大きく変わりました。その一方で、開発者一人が扱わなくてはいけない技術の高度化、複雑化により認知負荷が年々高まっていると言われています。認知負荷の高まりは生産性の低下に繋がるおそれがあり、せっかく導入した新技術がスポイルされかねません。 その解決策として期待されているのがPlatform Engineeringです。Team topologiesに基づいた適切なチーム分け、そして認知負荷を減らすことを目的とした共通プラットフォームを構築することによって、技術のコン トロール を取り戻し、組織のスケーラビリティと生産性を両立することができます。 本イベントは、そんなPlatform Engineeringの世界に深く潜り込むための絶好の機会です。最新のトレンド、実践的な知見、そしてこの分野の トップランナー たちとの交流を通じて、テク ノロ ジー の未来を切り拓いていきましょう。 ( 公式サイト より) 現地で発表された情報によると、申込者数は996名! Platform Engineeringの勢い、盛り上がりを感じますね〜。 当日の様子 タイムテーブル チーム トポロジー 著者のManuel Pais氏の基調講演に始まり、2トラック開催で各30分ずつのセッションが行われました。 現地参加のメンバーは各々好きなセッションを拝聴しましたが、(もちろん重複はあるものの)チームとしてのインプット量が凄まじいですね! その他、現地ではお昼ご飯にはサンドイッチ、おやつには カヌレ とコーヒーが提供されました。 (写真が食べ物しかなくてすみませんw) サンドイッチも カヌレ もおいしい! 各スポンサーブースではスタンプラリーが開催されており、おみやげをたくさんいただきました、スポンサー企業の皆さまありがとうございます! また、セッション終了後には懇親会も行われました。 ふりかえりやってみよう さて、現地参加の熱が冷めやらぬうちに、後日さっそくふりかえりを実施してみました。 実施するにあたって、事前に用意したフォーマットは下記です。 # 印象に残ったセッション ## タイトル ## 登壇者情報 ## スライド ## セッション概要 - セッションの内容を簡潔に ## 共有したい点、感想等 - どんな点に共感したか、疑問に思ったこと等 --- # 今後実施/挑戦したいこと - 参加してみてアクションを起こしたくなったものが何かあれば # 全体を通しての感想 - 率直な感想をご自由に それぞれが印象に残ったセッションを選択し、セッション概要と共有したい点/感想等を事前にまとめてもらいました。 以下、実際にまとめてもらったふりかえりの内容をご紹介します。 タイミーを支えるプラットフォームエンジニアリング・成果指標設計から考える組織作り事例の紹介 セッション紹介ページ speakerdeck.com セッション概要 インフラ領域のタスクを消化するいわゆるインフラチームから、プラットフォームエンジニアリングを体現するチームへ進化するための1年間の取り組みを紹介 当初、プラットフォームチームはインフラ関連の散発的なタスクをこなすだけのチームになっていたが、この体制を改善した チームの存在意義を明確に 言語化 成果指標を定義し、その指標に基づいて バックログ を再構築 システムメトリクスの観察と課題検知を スクラム イベントに組み込む コラボレーションモードを定義し(チーム トポロジー の拡張)、効率的な協働を促進 アウトプットドキュメントのフォーマットを整理 共有したい点、感想等 チームの存在意義や重要視する指標を定義し、課題探索の方法や他部署との関わり方をルール化することで、チーム内の目的意識を合わせるとともにミッションを体現するための施策に取り組むことができておりとても参考になった 成果指標を定義した背景として「説明可能であることの価値」を説いておりとても共感した 今後実施/挑戦したいこと プラットフォーム提供者として、作ったものをより使いやすくするために、マニュアルやリリースノート等のドキュメントのフォーマット決めと開発本部全体への周知ができると良いなと感じた 全体を通しての感想 立ち上がったばかりのプラットフォームチームのあり方がまとまっており、参考にしたい部分が多かった ドキュメンテーション や周知はストリームアラインドチームとの接点にもなるし信頼貯金にもつながるので積極的にやっていきたいと思った 明日から始める持続可能な ドキュメンテーション 戦略 セッション紹介ページ speakerdeck.com セッション概要 プラットフォームチームとして提供している技術ドキュメントの継続的な運用方法の紹介 構造品質よりも目的やゴールの達成がより重要(=機能品質) どんなに品質の高いドキュメントを書いても徐々に腐るもの ドキュメントのライフサイクルを意識した、具体的な改善方法を紹介 レビューのポリシーとフローの定義 メンテナンスポリシーの定義 メトリクスを指標として追う(鮮度と有効性) 想定読者に利用されているか(閲覧数) 共有したい点、感想等 「開発組織のポテンシャルを解放する」というチームのミッションがかっこいい!成果の最大化はよく聞くけど、この言い回しすてき! ドキュメントもプラットフォームの一部という考え方に気づけた 提供する機能だけに重きを置くのではなく、開発者がいかに自律的に使ってもらうかを意識してドキュメントの整備にここまで力を入れられているのは会社としてすごい たしかに業務をしていて資料を探している時間ってとても多いし、このドキュメント正しいのか?とメンテ状況を考えるのしんどいですよね(実態と合っていなかったりするとあちゃ〜ってなる) ドキュメント管理もデータドリブンでとてもよい取り組みだと思った、データは正義 今後実施/挑戦したいこと 今後SRE課で提供するもの、管理するものに関してはしっかりドキュメントもメンテナンスフローを構築したい リリース等のプロセス改善をしていく上で、本当に開発チームが楽になったのか?認知不可が下がっているのか?は常に意識していかないといけない 全体を通しての感想 改めて、プラットフォームは開発チームに強制的に使ってもらうものではなく、あくまでも開発チームを助けるもの(求められているもの)であるという理解 プラットフォームチームとして活躍している他社の事例を目の当たりして、弊社の組織のあり方を再考するよい機会になった モノリス 開発の名残からの脱却、マルチプロダクト開発における多様な開発者のニーズに応える使い勝手と堅牢性を追求した認可基盤刷新の過程と工夫 セッション紹介ページ speakerdeck.com セッション概要 アプリケーションから認可機能を切り出していくまでに検討したこと、安全に移行するまでにやったことなどの紹介 共有したい点、感想等 移行後の認可基盤にバグがあった場合、本来アクセスできない画面が見えてしまうといったこともあるかもしれないので、既存の認可機能を残しつつ新認可基盤もリリースし、認可機能と認可基盤の挙動としてどちらも同一であることを確認する方法をとっていた点が参考になった 万が一のためにガードレールを敷いて、認可基盤の信頼性を担保するというのはとても勉強になった 今後実施/挑戦したいこと 開発プロセス の自動化や共 通化 を進めることで、開発者の生産性向上に貢献し、開発チームが高品質なソフトウェアを迅速に提供できる手助けができたらよいなと感じた 全体を通しての感想 複数のプロダクトを展開する他社の開発体制と自社の体制との差を再認識するよい機会となった What is Platform as a Product and Why Should You Care セッション紹介ページ ※チーム トポロジー の著者Manuel Pais氏による基調講演 ※スライドは非公開 セッション概要 プラットフォーム構築の目的はストリームアラインドチーム(SA-T)の認知負荷を下げること 扱いが難しく、認知負荷を上げるプラットフォームは浸透しない SA-Tが プラットフォーマー の顧客である プラットフォームはプロダクトとして扱うべき。なので、ユーザー(SA-T)へのアプローチはプロダクトと同様にとるべきである 目的(Mission)を見失わない マーケティング を行いニーズを掘る(イネーブリングモードのコミュニケーションなどが有効) 小さく始め、素早く PMF を目指す 次の マーケティング のサイクルにつなげるために、計画的にフィードバックを得る プロダクトを購入するかはユーザーのオプションである=魅力的なプロダクトを作ろう プロダクトの開発には投資が必要なので、投資家であるビジネスサイドの関心事にフォーカスして投資を得よう プラットフォームの持続可能性を保つための4つの柱 プラットフォームを信頼してもらう サクセスストーリーを共有していく プラットフォームチーム自身のconfidence(自信)が不可欠 ユーザーのconfidence(自信)が不可欠 共有したい点、感想等 「ストリームアラインドチーム(開発チーム)がアプリケーション開発に専念できるようにする」ことが目的だが、これを実現するのは非常に困難 プラットフォームをプロダクトと捉えるとうまく進む、というところが凄く腹落ちした 多くの会社でプラットフォーム化が失敗する原因もよく分かった エンジニア側の問題 ビジネス観点が足りないことが多く、収支が見込めないサービスは投資してもらえない ビジネス側の問題 エンジニアリングの観点が足りないことが多く、投資に足るサービスであるか否かを正確に判断できない うまく行っている会社は上記2者間の相互理解がちゃんとできているなと思った 今後実施/挑戦したいこと 現プラットフォーム化プロジェクトで90点を目指す ストリームアラインドチームの認知負荷を下げるための改善を実施 フィードバックを得る為のメトリクスの整備 利用者数を計画的に増やす 全体を通しての感想 Platform Engineeringは実態として 社内ベンチャー に近い存在であり、それが難しい理由の一つだと感じた しかし、顧客は社内の仲間であり、フィードバックや相互理解の機会が通常のプロダクトよりも多くあるはずなので、これらの機会をしっかりと活用することで成功の可能性が高まると思った ビジネスサイドの方々にも基調講演を見ていただく機会があれば、相互理解がより進みやすいのではないかと感じた Platform Engineering at Mercari セッション紹介ページ speakerdeck.com セッション概要 MercariのPlatform Engineeringチームがプラットフォームをどのように立ち上げ、発展させてきたのか、その中から得られた学びについて紹介 共有したい点、感想等 各チームが独自にプラットフォームを作ると、重複が生じて無駄が発生してしまう=1つの会社で1つのプラットフォームであるべき 「古いシステム」=「価値の高いシステム」であるという視点 モノリシックなシステムは新しい基盤に移行するのに時間がかかり、すべてをマイクロサービスにするのは現実的ではないため、 モノリス のまま移行する 新しい基盤にすべてを移行するメリットとして、古いインフラの管理をなくすことができる 今後実施/挑戦したいこと もし今各商材でプラットフォーム的なものが乱立しているなら、共 通化 することで無駄を削れるのではないかと思った 全体を通しての感想 異動してから初のSRE(Platform Engineering)系のイベントだったが、話がちょっとわかるぞ!となった 基調講演で「ストリームアラインドチームが必要としているプラットフォームを提供する」とあったが、まずはチームが求めるものが本当に問題解決につながるかどうかをよく考えた上で作ることが大切だと思った いつPlatform Engineeringを始めるべきか?〜レバテックの ケーススタディ 〜 セッション紹介ページ speakerdeck.com セッション概要 レバテックにおけるプラットフォームチーム(基盤チーム)のこれまでの変遷を辿りながら、役割の整理や組織の再編といったリアルな取り組みを紹介 共有したい点、感想等 プラットフォームとして何を提供するかしっかりと定義する事が重要 ストリームアラインドチームが実際に困っている事を改めて整理して、自分たちが出来ることを考えている 日々の運用でかつかつになっている、技術的な負債を抱えた レガシーシステム を保守している等 自分たちがやれることに合わせて組織を再編、ケースによってはチームを撤廃して他チームへ合流 SREとプラットフォームチームを分けるべきか否かについては組織規模による チームが多すぎると動きにくくなるので2ピザチームくらいが適切 いずれもストリームアラインドチームありきなのでその成熟度にもよる ストリームアラインドチームが事業に貢献できているか?もしできていないとしたら阻害要因は何かを考えるのが重要 上記を解決するためにプラットフォームエンジニアリングが有効なのであれば、その時が始めるタイミング 今後実施/挑戦したいこと 改めてストリームアラインドチームの困りごとを考える必要があると思った もう一度、As-Is / To-Beを関係者と話す機会を持ちたい 全体を通しての感想 プラットフォームエンジニアリングがBuzz Wordな事もあって飛びつきたくなる状態で、改めてその必要性を考える良い機会になった 総括 以上、『Platform Engineering Kaigi 2024』に参加したメンバーのふりかえりの内容をご紹介しました。 今回のカンファレンスでは、最新のPlatform Engineeringのトレンドや実践的な事例が多数紹介され、非常に有意義な時間を過ごすことができました。特に、現地に参加したことにより、リモートでは得られないリアルタイムでの情報共有や、他社のエンジニアの皆さまとの直接的なネットワーキングの機会を得ることができました。 また、課内のメンバーで参加したことにより、単純にインプットが増えただけでなく参加者同士での情報共有や議論の場が持てたことで、理解をより深めることができたのではないかと思います。 スタッフの皆さま、登壇者の皆さま、企画運営本当にお疲れ様でした。そしてありがとうございました! Platform Engineering Kaigi 2024は無事に終了致しました! 多くの方にご参加頂きありがとうございました! #PEK2024 pic.twitter.com/8mF8UW5Dq0 — Platform Engineering Kaigi / クラウド ネイティブイノベーターズ協会 (@cnia_pfem) 2024年7月9日 (セッション終了後の集合写真!会場も綺麗でした〜) そして、来月はついに『 SRE NEXT 』が開催されます(今年は2Days!)。 弊社SRE課のメンバーも参加予定なので、またその様子もお伝えできればと思います! 年に1度の技術イベント「RAKUS Tech Conference」を開催します!! 今年も ラク ス開発本部主催の技術カンファレンス、「RAKUS Tech Conference 2024」を開催します! 「RAKUS Tech Conference」は、 SaaS 開発における取り組みや知見を紹介する、 ラク ス開発本部主催の技術カンファレンスです。 ラク ス開発本部のミッションに込めた想いをエンジニア/デザイナーが生の声でお届けします。 皆さまのご参加、お待ちしております! techcon.rakus.co.jp
アバター
はじめに Webアプリケーションにおけるレートリミット、サーキットブレーカー、リトライの役割 リトライ サーキットブレーカー レートリミット レートリミット、サーキットブレーカー、リトライの実装 サンプルアプリケーションの実装 リトライ、サーキットブレーカー、レートリミットを追加 まとめ 年に1度の技術イベント「RAKUS Tech Conference」を開催します!! はじめに こんにちは!エンジニア2年目のTKDSです。 今回は、レートリミット・サーキットブレーカー・リトライについて調べた内容を紹介し、ライブラリを使ってGoで実装してみます。 Webアプリケーションにおけるレートリミット、サーキットブレーカー、リトライの役割 リトライ リク エス トが失敗した場合に再試行します。 リトライは、一時的な障害に対して効果を発揮します。 ネットワークの瞬断やサービスの一時的な過負荷など、やり直せば解決できそうな問題による失敗をシステム内のリトライでカバーすることで、ユーザーからは特に問題なく見える状態を維持したまま処理失敗の リカバリ ーができます。 サーキットブレーカー サービスを監視し、設定した条件がみたされると「オープン(リク エス トを受け付けない)」状態になり、しばらくすると「ハーフオープン(一部だけ受け入れ)」状態になり、システムが回復したかどうか一部のリク エス トを通して確認します。 回復したことが確認できれば「クローズ(通常状態)」に、だめなら「オープン」になります。 サーキットブレーカーは、復旧に時間のかかる障害に対して効果を発揮します。 そのままリトライし続けても回復する見込みが低い、もしくは回復まで時間がかかる場合、一旦アクセスを遮断することで障害が起きたサービスへの無駄なアクセスや無駄なリソースの消費を避けることができ、サービスが回復するまでの時間を稼ぎます。 レートリミット 設定した以上のリク エス トが来たときに、一時的にアクセスを制限します。 レートリミットを使うとサービスに過負荷がかかることを防ぐことができます。 また、 DoS攻撃 などからアプリケーションを守ることができます。 これらの機能を採用することでシステムの耐障害性、安定性、パフォーマンスを向上させられます。 レートリミット、サーキットブレーカー、リトライの実装 この節では、Goで実際にレートリミット、サーキットブレーカー、リトライの機能を実装していきます。 サンプルアプリケーションの実装 今回はライブラリを活用して実装していきます。 自分で1から実装しない理由はいくつかあります。 多くの人が利用しているライブラリはバグが発見されやすく、自分で実装するより信頼性が高い 採用時点でのベストプ ラク ティスを適用できる 複雑な動作の適切な処理を自身で考える必要がない このような観点からライブラリを使います。 以下がサンプルアプリケーションです。 リク エス トパラメータに指定したURLにアクセスし、存在する場合はカウントを1プラスし、ない場合はエラーを返します。 package main import ( "context" "errors" "fmt" "net/http" "os" "os/signal" "syscall" "time" "github.com/go-redis/redis/v8" "golang.org/x/exp/slog" ) var ( rdb *redis.Client ) func init() { rdb = redis.NewClient(&redis.Options{ Addr: "redis:6379" , // Redisサーバーのアドレス Password: "" , // パスワードなし DB: 0 , // デフォルトのDB }) } func hostExists(url string ) bool { resp, err := http.Get(url) if err != nil { return false } defer resp.Body.Close() return resp.StatusCode == http.StatusOK } func handler(w http.ResponseWriter, r *http.Request) { host := r.URL.Query().Get( "host" ) if host == "" { http.Error(w, "Host parameter is missing" , http.StatusBadRequest) return } if hostExists(host) { count, err := rdb.Incr(context.Background(), "counter" ).Result() if err != nil { http.Error(w, "Could not increment counter" , http.StatusInternalServerError) return } fmt.Fprintf(w, "Counter: %d \n " , count) } else { http.Error(w, "Host not found" , http.StatusNotFound) } } func main() { addr := ":8080" handler := http.HandlerFunc(handler) server := &http.Server{Addr: addr, Handler: handler} idleConnsClosed := make ( chan struct {}) go func () { c := make ( chan os.Signal, 1 ) signal.Notify(c, os.Interrupt, syscall.SIGTERM) // SIGINT, SIGTERM を検知する <-c ctx, cancel := context.WithTimeout(context.Background(), 10 *time.Second) defer cancel() slog.Info( "Server is shutting down..." ) if err := server.Shutdown(ctx); err != nil { if errors.Is(err, context.DeadlineExceeded) { slog.Warn( "HTTP server Shutdown: timeout" ) } else { slog.Error( "HTTP server Shutdown: " , err) } close (idleConnsClosed) return } slog.Info( "Server is shut down" ) close (idleConnsClosed) }() slog.Info( "Server is running on " , addr) if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { slog.Error( "HTTP server ListenAndServe: " , err) } <-idleConnsClosed } docker compose up --build で起動します。 成功するリク エス トと失敗するリク エス トを送って動作確認をしてみましょう。 成功: curl "http://localhost:8080?host=http://example.com" 失敗: curl "http://localhost:8080?host=http://.com" 下の画像のように動作確認ができます。 リトライ、サーキットブレーカー、レートリミットを追加 サンプルにリトライ、サーキットブレーカー、レートリミットを追加していきます。 コードは以下の通りです。 変更が入った、initとhostExists、handlerだけ記載します。 詳細は Github をみてください。 func init() { // Redisサーバーのアドレスを設定 rdb = redis.NewClient(&redis.Options{ Addr: "redis:6379" , // Redisサーバーのアドレス Password: "" , // パスワードなし DB: 0 , // デフォルトのDB }) cb = gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Redis" , Timeout: 30 * time.Second, ReadyToTrip: func (counts gobreaker.Counts) bool { return counts.ConsecutiveFailures >= 3 // 3回連続失敗でトリップ }, OnStateChange: func (name string , from gobreaker.State, to gobreaker.State) { log.Println( "Circuit breaker state changed" , "name" , name, "from" , from.String(), "to" , to.String()) // サーキットブレーカーの状態が変わるたびにログ出力 }, }) rateLimiter = ratelimit.New( 1 , ratelimit.Per( 10 *time.Second)) // 1リクエスト/秒 client = retryablehttp.NewClient() client.RetryMax = 3 // 最大3回リトライ } func hostExists(url string ) bool { req, err := retryablehttp.NewRequest( "GET" , url, nil ) if err != nil { return false } resp, err := client.Do(req) if err != nil { return false } defer resp.Body.Close() return resp.StatusCode == http.StatusOK } func handler(w http.ResponseWriter, r *http.Request) { // レートリミットの適用 rateLimiter.Take() host := r.URL.Query().Get( "host" ) if host == "" { http.Error(w, "Host parameter is missing" , http.StatusBadRequest) return } if hostExists(host) { // サーキットブレーカーの適用 body, err := cb.Execute( func () ( interface {}, error ) { count, err := rdb.Incr(context.Background(), "counter" ).Result() if err != nil { return nil , err } return fmt.Sprintf( "Counter: %d \n " , count), nil }) if err != nil { http.Error(w, "Could not increment counter" , http.StatusInternalServerError) return } fmt.Fprintf(w, body.( string )) } else { http.Error(w, "Host not found" , http.StatusNotFound) } } では同様に、起動して動作確認していきます。 docker compose down -v してきれいにしておきましょう。 docker compose build --no-cache でビルドし、 docker compose up で起動します。 リトライを起こすリク エス ト リトライはリク エス トが失敗した場合に起こります。 curl "http://localhost:8080?host=http://.com" を実行すると先程と違い、retryのログがサーバー側に出力されていることがわかります。 これでリトライが機能していることが確認できました。 レートリミットを起こすリク エス ト レートリミットの部分を以下のように変更しましょう。 このライブラリでは、レートリミットを超えると指定した時間処理を待機するようになっています。 10秒間に1回のリク エス トに制限してあります。 レートリミットがかかると、リク エス トに10秒かかっていることがわかります。 これで、レートリミットが機能していることが確認できました。 サーキットブレーカーを起動するリク エス ト 今回のサーキットブレーカーは3回連続失敗で、30秒間 タイムアウト するようにしています。 まず、起動しているRedisを止めます。 これでRedisへのアクセスが失敗するようになりました。 サーキットブレーカーの変化がログに出力されています。 三回失敗したあとにサーキットブレーカーの変化が起きています。 これでサーキットブレーカーの動作確認ができました! まとめ 今回はレートリミット・サーキットブレーカー・リトライについて調べた内容を紹介し、ライブラリを使ってGoで実装しました。 ライブラリを使えば比較的簡単に実装できるので、ぜひ実装してみて下さい。 マイクロサービスには必須の機能だと思うので、記憶にとどめて置きたいと思います。 ここまで読んでいただきありがとうございました! 年に1度の技術イベント「RAKUS Tech Conference」を開催します!! 今年も ラク ス開発本部主催の技術カンファレンス、「RAKUS Tech Conference 2024」を開催します! 「RAKUS Tech Conference」は、 SaaS 開発における取り組みや知見を紹介する、 ラク ス開発本部主催の技術カンファレンスです。 ラク ス開発本部のミッションに込めた想いをエンジニア/デザイナーが生の声でお届けします。 皆さまのご参加、お待ちしております! techcon.rakus.co.jp
アバター
RAKUS Tech Conference 2024とは? 開催概要 開発本部長メッセージ RAKUS Tech Conference 2024の見どころ 本イベントを視聴・参加するメリット!! 申込特典! タイムテーブル 過去のRAKUS Tech Conference RAKUS Tech Conference 2022 RAKUS Tech Conference 2023 参加者からのフィードバック ご参加お待ちしております! 技術広報のyayawowoです! 今年も ラク ス開発本部主催の技術カンファレンス、「RAKUS Tech Conference 2024」を開催します! techcon.rakus.co.jp RAKUS Tech Conference 2024とは? 「顧客をカスタマーサクセスに導く圧倒的に使いやすい SaaS を創り提供する」 開発本部のミッションに込めた想いをエンジニア/デザイナーが生の声でお届けします。 株式会社 ラク スは「ITサービスで企業の成長を継続的に支援します!」をミッションに掲げ、経費精算システムの「楽楽精算」や、メール共有・管理システムの「メールディーラー」など延べ83,000社を超えるお客様に SaaS サービスを提供してきました。 「RAKUS Tech Conference」は、 SaaS 開発における取り組みや知見を紹介する、 ラク ス開発本部主催の技術カンファレンスです。 開催概要 日時: 2024/8/7(水)14:00-18:00 会場: オンライン(Zoom) ※connpassのメッセージ機能、およびイベントページ内の「参加者への情報」欄にて開催前にURLを通知いたします。 参加費: 無料 主催: ラク ス RAKUS Tech Conference 2024 公式サイト: https://techcon.rakus.co.jp/2024/ ハッシュタグ : #RAKUSTechCon 開発本部長メッセージ ラク ス開発本部は「顧客をカスタマーサクセスに導く圧倒的に使いやすい SaaS を創り提供する」をミッションに掲げています。   私たちは、2000年代初期の SaaS 開発時から徹底して顧客視点を大切にし、顧客のペインポイントを理解し、その解決に向けて様々な取り組みを行ってきました。一方、組織が急拡大する中で、エンジニア一人ひとりの顧客に対する解像度が低下するという課題にも直面しました。   本カンファレンスでは、私たちが直面した困難とその乗り越え方、顧客視点を保つための具体的な取り組みを、CTOやPdM・EM・エンジニア・デザイナーが現場のリアルな声でお届けします。   顧客志向の開発を重視し、真のカスタマーサクセスを目指す皆様に、私たちの知見とインスピレーションを少しでも共有できればと思っています。 RAKUS Tech Conference 2024の見どころ 本イベントを視聴・参加するメリット!! ARR300億円越えの SaaS 開発組織の裏側を知ることができる ラク ス開発本部の戦略や現状の課題、今後のビジョンを知ることができる 急拡大するマルチプロダクト SaaS 開発の知見を持ち帰ることができる 長期プロダクトに携わるエンジニアの働き方が聞ける 開発プロセス 内のデザイナーのあり方を知れる インフラ部門の技術選定の秘訣を知ることができる ラク スは生成AIの活用にどう取り組んでいるか? 申込特典! お申込みの方へ後日、RAKUS Tech Conference 2024の アーカイブ 動画を配信いたします。 ※当日参加できない方も対象となります。 タイムテーブル 開始時間 タイトル 登壇者 14:00 オープニング 14:10 ラク スCTOが語る顧客視点を重視したプロダクト開発 開発本部 本部長 兼 執行役員   公手真之 14:40 マルチプロダクトでのプロダクトマネージャーのリアル 東京開発統括部 製品管理課 課長  稲垣剛之 15:10 拡大するマルチプロダクト SaaS の顧客理解にデザイン組織はどう取り組んでいるか 開発推進部 プロダクトデザイン課 課長  小林肇 開発推進部 プロダクトデザイン課  今村 沙穂理 15:30 急成長する大規模プロダクト開発のマネジメント課題とアプローチ 東京開発統括部 楽楽精算開発部 部長  髙橋康弘 楽楽精算開発部 開発1課 課長  小宮山和彦 楽楽精算開発部 開発1課  涌井友輔 16:00 パフォーマンス向上とリソース管理のためのアプローチ 株式会社 ラク スライト クラウド 企画課  牧野寛知 株式会社 ラク スライト クラウド BMバックエンド開発課  上原崇 16:20 急成長するサービスを支えるためのインフラ戦略 インフラ開発部 副部長  藤井靖弘 16:40 楽楽精算のQA改革 東京開発統括部 QA課  金子佳樹 17:00 新たな顧客課題に挑む17年目の進化とモダナイゼーション 大阪開発統括部 配配メール開発課 課長  大塚正道 大阪開発統括部 配配メール開発課  井上良太 開発推進部 フロントエンド開発1課  亀ノ上孝雄 17:30 クロージング トーク 大阪開発統括部 統括部長  矢成行雄 プログラム詳細は、以下サイトをご確認ください。 RAKUS Tech Conference2024 RAKUS Tech Conference 2024 - connpass RAKUS Tech Conference 2024|IT勉強会・イベントならTECH PLAY[テックプレイ] 過去のRAKUS Tech Conference 今回の開催で3回目の開催となる、RAKUS Tech Conferenceの今までの発表内容を振り返ってみたいと思います。 RAKUS Tech Conference 2022 初めてRAKUS Tech Conferenceを開催した年でした! 発表内容は以下の通りです。 【発表内容】 ラク スのエンジニア組織について 楽楽精算のサービスと共に成長するエンジニア組織の3年間とこれから トラブルゼロで乗り切ったTypeScript移行 息の長いサービスのPHP8バージョンアップで見えた課題と解決法 進化を止めない、"レガシー"との向き合い方 SaaS マルチヒット メーカー ラク スのインフラ戦略 発表資料は以下ブログにまとめておりますので、ご興味ある方は是非ご確認ください! tech-blog.rakus.co.jp RAKUS Tech Conference 2023 ラク スではローンチ20年を超えるプロダクトもあり、決して目新しい技術ばかりを扱っているわけではありませんが、一人ひとりが地道な" カイゼン "のための努力、そして"挑戦"を続けています。 そんな弊社だからこその取り組みを発表させていただきました。 【発表内容】 短納期でも進化をあきらめなかった新規プロダクト開発 フロントエンド横断組織のチーム トポロジー ベテラン社員が抜けても若手が成長できるエンジニア組織づくり デザイン組織が社内下請けから脱却するためにやったこと ゼロから始める クラウド ネイティブ 「開発優先」の中で取り組む組織的な新技術への挑戦 発表資料は以下ブログにまとめております。 是非ご確認ください! tech-blog.rakus.co.jp 参加者からのフィードバック 過去RAKUS Tech Conferenceに参加された方からは、以下のようなコメントをいただいております。 ラク スさんの実際の開発チームについて知ることができました。ありがとうございました。 各パート非常にわかりやすく発表していただいていたので、とても勉強になりました。 単なる最新技術の紹介でなく、地に足のついた実際の業務に役立てられるお話を聞けました。御社の雰囲気も伝わってきて大変興味深く拝見させていただきました。 Cloud利用の理想と現実のような、現場ならではの内容など大変参考になりました。 興味のあった話をあますことなく聞けてとてもおもしろかったですし、有用でした。 今回の話を実際の業務で活かせるところを見つけて、活用したいと思います。 ベテランの方だけでなく、若手でもイベントの運営をしたり、リーダーが行っていた一部の業務に携われるといったように、裁量をもって仕事に取り組める環境が良いと感じました。 単発の勉強会は参加していましたが通しのイベントは初めてでした。ボリュームがあってよかったです。 稼働している レガシーシステム からモダンな開発システムへの移行期の悩みや、エンジニアやビジネス側にUIUXデザインの重要性の理解が進みづらいという点も非常に共感いたしました。          ※RAKUS Tech Conference 2022、RAKUS Tech Conference 2023の参加後アンケートより引用 ご参加お待ちしております! 開発本部のミッションである「顧客をカスタマーサクセスに導く圧倒的に使いやすい SaaS を創り提供する」ために開発本部一丸となって、日々精進しております。 当日参加できない方も申込特典として アーカイブ 動画をお送りしますので、是非お気軽にご参加ください! 弊社の技術取り組みが、皆さまにとって少しでもお役に立てれば幸いです。 皆さまのご参加、お待ちしております! techcon.rakus.co.jp
アバター
はじめに こんにちは。楽楽販売開発課のm_tkoとthree_yagiです。 今回は、私たちが所属しているサポート対応チームの業務を紹介します。 目次 はじめに 目次 サポート対応とは? 組織体制 取り組み 仕様確認系のお問い合わせ 調査系のお問い合わせ 工夫している点 回答観点について 通知botの運用 お問い合わせの傾向分析 今後の展望 最後に サポート対応とは? まず、サポート対応とは何かについて説明します。 基本的に、お客様からのお問い合わせはカスタマーサポートを担っている部署が回答をしています。 カスタマーサポートの基本的なフロー ただ、そのお問い合わせの中にはエンジニア視点での調査が必要なものがあります。 そういったお問い合わせをエンジニア側で引き受けて調査を行うことを「サポート対応」と呼んでいます。 エンジニア側で問合せ対応を行う場合のフロー エス カレーションされるお問い合わせは、仕様確認や調査が主になります。 ラク スだけに存在するポジションではなく、どのシステム会社でも似たような業務をされている立場の方が多いと思います。 一部では「 エス カレーションエンジニア」という名称で呼ばれることもあるそうです。 組織体制 現在、サポート対応チームは4名で業務を回しています。 役割自体には大きな差はなく、日替わりで担当者を決めて対応に当たっています。 問い合わせが来るタイミングや量はまちまちなので、開発業務と並行して対応にあたっています。 取り組み カスタマーサポートチームから エス カレーションされたお問い合わせは、社内で運用している楽楽販売に登録されます。 具体的にどういったお問い合せが来るのか、それらのお問い合わせについてサポート対応チームがどのような対応を行っているのかをご紹介します。 仕様確認系のお問い合わせ 楽楽販売では、利用目的に合わせて柔軟に対応できる高いカスタマイズ性が特徴の一つとなっています。 それゆえ設定できる箇所が多く、仕様を完全に把握するのが難しいという側面があります。 そのため、お客様から以下のようなお問い合わせをいただくことがよくあります。 「〇〇〇という設定は可能か」 「〇〇〇という挙動は正しいか」 「〇〇〇との連携は可能か」 このようなお問い合わせのうち、1次窓口であるカスタマーサポートチームでは判断のつかない仕様については、サポート対応チーム向けに仕様確認依頼が登録されます。 依頼が登録されるとサポート対応チームでは以下のような調査を行い、仕様を確認して回答しています。 検証環境での動作確認 当時の設計資料の確認 機能の設計・開発担当者への ヒアリ ング コードの調査 地道な調査が必要になりますが、これらのお問い合わせから仕様不備が見つかることもあり、サポート対応チームの大事な仕事の1つとなっています。 調査系のお問い合わせ 調査系のお問い合わせとしては以下のようなものがあります。 「〇〇〇を実行したが想定通りの結果にならなかった」 「〇〇〇というエラーが発生した」 「楽楽販売から送信したメールが届かない」 設定ミスなどが原因であればカスタマーサポートチームが調査・回答を行いますが、設定に問題がなかった場合や、システム不備の可能性があるものについてはサポート対応チームに エス カレーションされ、こちらで調査を行います。 調査では主に以下のようなことを行っています。 関連設定の確認 本番環境のログの調査 エラーが出力されていないか 想定通りのログが出力されているか 意図しない操作が行われていないか 検証環境での再現確認 不具合が確認された場合は、不具合の原因調査 これらの調査を行い、発生原因を探っていきます。 内容によっては、インフラチームに依頼して必要なデータを取得したり、設定を複製した環境で デバッグ を行ったりと取れる手段を駆使しながら調査を行います。 原因が判明した場合は、お客様の環境に合わせた回避方法の検証も行います。 事象の「原因」と「回避方法」をカスタマーサポートチームに回答して完了となります。 工夫している点 回答観点について 楽楽販売は設定次第で様々な業務に利用することができるので、お客様ごとに利用目的は異なります。 そのため、お問い合わせ対応では以下を考えながら取り組むようにしています。 なぜこの機能を使っているのか 機能を通して実現したい動きはなにか どういった状態であれば理想的か 単純にお問い合わせ内容に対して回答するだけでなく、お問い合わせに至った背景を理解し お客様の目的に合わせた回答をすることで、納得度の高い回答を目指しています。 通知 bot の運用 調査系のお問い合わせでは「業務が止まってしまっているので数時間以内に原因と回避方法を教えてほしい」といった急ぎのものが来ることがあります。 こういったお問い合わせにもすぐ対応できるように、お問い合わせが社内の楽楽販売に登録・更新された際に社内のチャットツールでお知らせする通知 bot を運用しています。 お問い合わせ登録時の bot による通知 担当者の割り振りや対応の進捗の共有もチャット上で行っています。 お問い合わせの傾向分析 対応が完了したお問い合わせについては、内容に応じてカテゴリを割り振り傾向分析を行っています。 月次でカテゴリ毎の問い合わせ件数や対応にかかった時間などを集計し、どういったカテゴリのお問い合わせが増えているかを分析しています。 分析した結果は今後のお問い合わせ対応の改善を行うための参考としたり、「お問い合わせが多い機能 = 改善の余地がある機能」としてシステム改善に繋げています。 今後の展望 サポート対応チームの現在の優先事項は 「エンジニア向けのお問い合わせ件数を減らす」 ことです。 そのために、現在はカスタマーサポートを担っている部署側でお問い合わせを解決できるように、 エンジニア側によくお問い合わせが来る質問の一覧を作成 技術的な用語の説明資料を作成する といったアクションを行っている段階です。 しかし、最終的に目指すべきゴールは 「お客様の疑問・もやもやを無くす」 ことです。 実現方法はいくつかあげられるかとは思いますが、やはりエンジニアとしてはシステムの改善を行うことでお客様の満足度向上に繋げていきたいです。 現状はお問い合わせの対応がメインとなっており、システムの改善までは至れていない状態です。 ただ、逆に言えばお客様との距離が近い位置にあり、どういった課題感があるのかを身をもって知ることができるのが強みだと考えています。 その強みを生かして、今後は お問い合わせ内容の分析 ➡ システムの改善点の抽出 ➡ システム改善の設計・実装 を一手に担えるようなチームにしていきたいです。 最後に 楽楽販売開発のサポート対応チームについて紹介させていただきました。 あまり注目されない、且つ地味なポジションではありますが、システムを支える上では必要不可欠な存在だと思っています。 お客様に快適にシステムをご利用いただくために、今後も工夫しながら業務を続けていきます。
アバター
BigDecimalの値保持について BigDecimalから値の抽出 誤った表記変換方法 正しい文字列を取得する方法 まとめ お金の計算など正確に Java で計算をするうえで欠かせない BigDecimal ですが、 一部 JDK バージョンで挙動に変更が入っていました。 この改修により問題に直面してしまったため備忘録がてら挙動をまとめることにしました。 BigDecimal の値保持について まず、本題に入る前に BigDecimal はどのように値を保持しているかを見てみましょう。 BigDecimal は以下の要素を保持しています。 intCompact 数値の 仮数 部を保持する intVal BigDecimal のスケーリングされていない値 precision 保持している 仮数 部の桁数 scale 少数のスケール では実際に見てみましょう。 BigDecimal bigDecimal1 = new BigDecimal( "3.14e+25" ); BigDecimal bigDecimal2 = new BigDecimal( "31400000000000000000000000" ); BigDecimal の内部値例 bigDecimal1は指数表現を指定し作成されているため intCompact には314、 precision には3、 scale には-23が格納されています。 また、bigDecimal1は指数表記なので intVal に値は保持されていません。 bigDecimal2は通常の数値表記を指定し作成されているため intCompact にはLong最低値、 intVal にはスケーリングされていない値、 precision には26が格納されています。 このように BigDecimal は同じ数値でありながらも内部の値が異なることがあるというパターンは存在します。 BigDecimal から値の抽出 それでは本題です。 先ほどの例で見た通り BigDecimal の値保持には2つのパターンがありました。 これらのtoStringすると以下のようになります。 bigDecimal1 : 3.14E+25 bigDecimal2 : 31400000000000000000000000 当然 BigDecimal 作成時に指定したものになりますね。 ここで例えば、この文字列を画面表示に使用したい場合について考えてみます。 3.14E+25 のように表示しても数値自体は誤りではないですが、 金額の表示などであれば非常にわかりづらいですよね。 ではbigDecimal2は良いとしてもbigDecimal1はどうすればよいでしょうか。 誤った表記変換方法 指数表記になってしまった BigDecimal を通常の数値表記の戻す方法として誤っている例を挙げてみます。 何を使用するかというと BigDecimal のメソッドの movePointRight(0) です。 movePointRight は小数点を右に指定した分だけずらすというメソッドです。 つまり右に小数点を0個ずらすということです。 BigDecimal bigDecimal1 = new BigDecimal( "3.14e+25" ).movePointRight( 0 ); BigDecimal bigDecimal2 = new BigDecimal( "31400000000000000000000000" ).movePointRight( 0 ); JDK のバージョンごとの結果は以下の通りになりました。 JDK バージョン bigDecimal1 bigDecimal2 8 31400000000000000000000000 31400000000000000000000000 11 31400000000000000000000000 31400000000000000000000000 17 3.14E+25 31400000000000000000000000 21 31400000000000000000000000 31400000000000000000000000 なんと JDK17だけ bigDecimal1が指数表記のままとなってしまっています。 ※以下は使用した JDK の ディストリビューション とバージョンです。 JDK バージョン Amazon Corretto 8 1.8.0_412 Amazon Corretto 11 11.0.23 Amazon Corretto 17 17.0.11 Amazon Corretto 21 21.0.3 正しい文字列を取得する方法 movePointRight(0) を使用した BigDecimal をtoStringで表示させた際にJDK17のときのみ 指数表記になってしまうということがわかりました。 では正しい値を取り出す方法はあるのでしょうか。 もちろん存在します。 BigDecimal のtoPlainStringメソッドです。 これを使用すると保持している内部データが異なっていても通常の数値表現(文字列)を返してくれます。 このメソッドは JDK 5から実装されているので問題になっていない JDK バージョンでも積極的に使用したいですね。 まとめ JDK バージョンによって BigDecimal が動作が一部異なるという現象に遭遇し今回詳しく調べて見ました。 JDK17でのみ挙動が異なっており、最新のLTSであるJDK21では発生していないので 今後修正される可能性もあるかもしれません。 しかし、 Java 側で通常の数値表記を取り出すメソッドが用意されているので今後はそれを使用したほうが良さそうです。 BigDecimal を使用する場面というのは間違うことが許されないような数値を扱う場面が殆どかと思います。 今後の更新も要チェックですね。
アバター
はじめに HTTPS(HTTP Over TLS)とは SSL/TLS HTTPSの流れ 実際に通信を観察 自己署名証明書の用意 サーバーの作成 WireSharkの準備 リクエストを送信して観察 まとめ はじめに エンジニア2年目のTKDSです! 普段何気なく使ってるほとんどのWebサイトが対応している HTTPS 通信の仕組みについて調べてみました。 本記事では、 Wireshark を用いて HTTPS の内部動作を解析し、どのようにしてデータが保護されているのかを具体的に解説します。 記事の後半では、 Wireshark を使って実際の通信データを観察し、暗号化プロセスの詳細を確認してみます。 HTTPS (HTTP Over TLS )とは HTTPS (HTTP Over TLS )は、HTTPの暗号化版で、ウェブサイトとブラウザ間の安全な通信を実現する プロトコル です。 TLS を使用して、HTTP通信を暗号化することで、データの機密性、データの整合性、通信先サーバーの信頼性を確認できます。 SSL / TLS SSL (Secure Sockets Layer)と TLS (Transport Layer Security)は、インターネット上でデータを暗号化して送受信するための プロトコル です。 これらの プロトコル は、ウェブブラウザとウェブサーバー間の通信を保護し、データの盗聴や改ざんを防ぐために使用されます。 SSL は1990年代初頭に Netscape 社によって開発されました。 最初のバージョンである SSL 2.0は1995年にリリースされましたが、セキュリティ上の 脆弱性 が発見され、1996年に SSL 3.0に置き換えられました。 その後、1999年に SSL 3.0を基にした TLS 1.0が登場し、現在では TLS 1.3が最新バージョンとして使用されています。 HTTPS の流れ HTTPS は次の流れで通信を行います。 クライアントがサーバーに HTTPS 接続を要求 サーバーが SSL / TLS 証明書(公開鍵も含む)をクライアントに送信 クライアントが証明書を検証し、サーバーの身元を確認 クライアントがセッション鍵(対称鍵)を生成 クライアントがセッション鍵をサーバーの公開鍵で暗号化して送信 サーバーが 秘密鍵 を使ってセッション鍵を復号、この時点で、クライアントとサーバーの両方が同じセッション鍵を共有、以降の通信はこのセッション鍵を使って暗号化 クライアントが暗号化されたHTTPリク エス トを送信 サーバーがリク エス トを復号して処理 サーバーが暗号化されたHTTPレスポンスを送信 クライアントがレスポンスを復号して表示 HTTPS の流れの図を以下に記載します。 暗号鍵をクライアントとサーバー間の通信で使うことで安全に通信していることがわかりました。 実際に通信を観察 次に HTTPS を観察してみます。 通信先のサーバーをGoで用意して、 curl で通信します。 自己署名証明書 の用意 今回使う証明書を用意します。 sudo apt-get update sudo apt-get install openssl openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt サーバーの作成 今回使用するhttpサーバーを用意します。 ファイル名はmain.goを想定しています。 起動は、 go run main.go で行ってください。 HTTPサーバー package main import ( "fmt" "net/http" ) func helloHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, World!" ) } func main() { http.HandleFunc( "/" , helloHandler) fmt.Println( "Starting HTTP server on :8080" ) if err := http.ListenAndServe( ":8080" , nil ); err != nil { fmt.Println( "Error starting HTTP server:" , err) } } HTTPS サーバー package main import ( "fmt" "net/http" ) func helloHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, World!" ) } func main() { http.HandleFunc( "/" , helloHandler) fmt.Println( "Starting HTTPS server on :8443" ) if err := http.ListenAndServeTLS( ":8443" , "server.crt" , "server.key" , nil ); err != nil { fmt.Println( "Error starting HTTPS server:" , err) } } WireShark の準備 通信のキャプチャは WireShark を使います。 以下の手順にしたがって準備してください。 インストール sudo apt-get update sudo apt-get install wireshark sudo dpkg-reconfigure wireshark-common sudo usermod -aG wireshark $USER newgrp wireshark 起動 sudo wireshark キャプチャするネットワークインターフェースの選択 今回は localhost なので、loを選択します。 キャプチャの開始 開始ボタンを押すとキャプチャが開始されます。 HTTPの場合、上部のフィルタに http.request and tcp.port == 8080 を入力します。 HTTPS の場合、上部のフィルタに tls and tcp.port == 8443 と入力します。 リク エス トを送信して観察 HTTP http用のサーバーを起動してからリク エス トを送る。 curl http://localhost:8080 通常のHTTP通信が行われているのが確認できます。 フィルタのhttp指定を外してすべての通信をみても、 https ではないので暗号化は行われていないことがわかります。 HTTPS HTTPS 用のサーバーを起動してからリク エス トを送る。 curl -k https://localhost:8443 TLS ハンドシェイクが行われていることが確認できます。 暗号化されているのでどのhttpメソッドを実行しているか、エンドポイントのパスはなにかなどは通信内容から読み取れなくなっています。 TLS の流れを少しみてみましょう。 Client Hello TLS (Transport Layer Security)接続の開始時にクライアントからサーバーに送信される最初のメッセージです。 クライアントがサポートするセキュリティ設定をサーバーに通知し、サーバーとクライアントの間で使用する暗号化方法の ネゴシエート を開始します。 Server Hello Server Helloをクライアントに送信し、使用する TLS のバージョン、暗号スイート、圧縮方法を確定します。 Change Cipher Spec, Application Data Change Cipher Specをクライアントに送信し、以降の通信が暗号化されることを通知 以上が TLS の流れでした。 まとめ ここまで読んでいただきありがとうございました! この記事ではHTTPと HTTPS の通信を観察し、通信内容を比較しました。 ふとした疑問から調べはじめた内容でしたが、知識の復習やツールの使い方を思い出す役に立ちました 。 普段意識せずに使っているものも、実際に調べてみることで、知識の定着につながりました。
アバター
こんにちは、モバイル開発チームのhyoshです。 弊社では各分野の特定のテーマに沿ってエンジニアが議論する「TechCafe」というイベントを定期開催しています。 そして先日私を含めた弊社モバイル開発チームが2度目となる「モバイルTechCafe」を開催しました! 今回のイベントでは「 Google I/O 2024とWWDC24で気になったセッション」について語り合いました。 弊社のメンバーが事前にまとめてきた情報にしたがって、他の参加者に意見を頂いて語り合いながら学びました。 今回はその内容についてレポートします。 Google I/O 2024 デベロッパー基調講演 Android 開発ツールの新機能 Google Play の新機能 Android の新機能 WWDC24 基調講演 Xcode16の新機能 Swiftの新機能 Swift Testingについて まとめ Google I/O 2024 公式ページ: Google I/O 2024 開催期間:2024/5/14 (現地時間) Google I/O は Google が毎年開催する開発者向けの大規模カンファレンスです。 モバイルエンジニアにとっては Android やFlutter開発における最新情報が入手できる場となっています。 本年度はやはりAI活用といったところが目玉になると見込まれていましたが果たして結果は…? デベロッパ ー基調講演 io.google セッション概要 基調講演ということもあり開発者ツール、 Android 、Flutter、Firebaseと幅広く開発者向けの新情報が発表されました。 注目されていたAI関連ではGemini 1.5 Flash の提供開始、GeminiAPI開発者 コンペティション 開催、Gemini NanoがPixel8 Proから搭載などやはり多くの時間を割いて紹介がされていました。 メンバーの感想 Gemini Nano は通信介さないので低遅延・セキュアなアプリ実装が可能。 Chrome にも搭載されるのでコスト低く 拡張機能 開発なども取り組むことができそう。 遂に Google が Kotlin Multiplatform(KMP) を公式サポート。Room等のライブラリもKMP対応されたし、今後も充実してくれれば移行もしやすく採用ハードルも下がりそう。 クラウド 開発環境の Project IDX がBeta版として公開。CodeOSSベースなので VSCode でFlutter開発している人には選択肢になるかも。環境構築不要なので勉強会とかにもよさそう。 Android 開発ツールの新機能 io.google セッション概要 恒例の最新版 Android Studio の紹介ですが本年度は Android Studio Koala が紹介されました。 目玉はやはりGeminiとの連携ですがそれ以外でも開発が便利になる新機能が目白押しで利用するのが楽しみになる発表でした。 メンバーの感想 チャットだけだったStudioBotからコード補完もできるGeminiに進化。選択範囲に対してプロンプトで細かい指示出せるのも使いやすそう。インライン ブレークポイント とかも地味に便利で嬉しい。 FirebaseはCrashlyticsがGemini連携し原因や対策を提案してくれるようになったので、クラッシュ調査で手早く洞察得るのに活用したい。 Google Play の新機能 io.google セッション概要 多様な国やデ バイス に対しても最適な表現をすることで更に深くリーチし、より安全なアプリ提供を実現できる新しい機能が紹介されました。 特にゲームアプリについてユーザーにより魅力を伝えファンを増やしていくプラットフォームとしていく事に力を注いでいる姿が印象的でした。 メンバーの感想 セキュリティポリシー 違反や不安定な サードパーティ ライブラリを審査時に教えてくれるのは助かる。 レビュー提出前に一度出したアプリを削除できる機能はずっと欲しかったのでありがたい。リリースプロセスの柔軟性を上げる事ができる。 Android の新機能 io.google セッション概要 基調講演でもフォーカスされていたGemini Nanoの活用例の他、最新OSである Android15の機能紹介 がされました。 メンバーの感想 Kotlin2.0からCompose コンパイラ がKotlin リポジトリ に同梱されるようになったので複雑な互換性管理がなくなり嬉しい。 Android15からEdge to Edgeがどのアプリでもデフォルトになりデザインが変わるので、次回のtargetSdk対応は苦労しそう。 WWDC24 公式ページ: WWDC24 - Apple Developer 開催期間:2024/6/10~6/14 (現地時間) WWDC は Apple が毎年開催する開発者向けの大規模カンファレンスです。 Apple の最新製品や技術が紹介されるのでエンジニアだけでなくファンにも待ち遠しいイベントですね。 iOS エンジニアとしては新OSや開発環境が気になるところですが当メンバーはどこに興味を持ったのでしょうか…? 基調講演 developer.apple.com セッション概要 数日間に渡るイベント全体のサマリともいえる基調講演は昨年度の Vision Proのように目玉となる製品が発表される再注目のセッションです。 今回は何と言っても待望の Apple 製品搭載AIである Apple Intelligence の紹介に当チームも湧き立ちました。 メンバーの感想 各アプリからシームレスにAI利用できるUIUXの作り込みはさすが Apple という感じ。 ChatGPTとも併用というのが意外だったけどハイブリッドで使い分けるのは互いの強みを活かせて最適なのかも。 Xcode16の新機能 developer.apple.com セッション概要 iOS 開発環境であるXodeについて最新機能が紹介されました。 期待されていたAI活用によるコード補完やプレビューや デバッグ 機能の強化など利用者にとっては気になる情報が盛りだくさんでした。 メンバーの感想 macOS が最新の Sequoia で Apple Siliconという条件は厳しいけどコード補完を早く使いたい。完全ローカルで動作して学習データにも利用されないとのことでプライバシーにも配慮されてるのはさすが。 Copilotも使っているが並行して試せそうなので回答を比較してみたい。 Swiftの新機能 developer.apple.com セッション概要 今年で10周年という事でSwiftの歴史を振り返りつつ最新のSwift6の新機能が紹介されました。 Swift6では特に非同期でのデータ競合の安全性を向上させる新しい言語モードが強調されていました。 メンバーの感想 歴史を見ているとSwift2→3は破壊的変更が多く永遠にビルドが通らず辛かったことを思い出した。 Mac 前提というのが試したくてもハードル高いので今後環境に依らず開発できるように クロスプラットフォーム 開発機能に注力してくれるのは嬉しい。 Swift Testingについて developer.apple.com セッション概要 Swiftを使用してコードをテストするための新しいパッケージ、Swift Testingについて紹介されました。 従来のテスト フレームワーク であるXCTestの辛い部分が大幅に改善されていそうで非常に期待感の大きい内容でした。 メンバーの感想 記述がシンプルになり可読性が大きく上げられそう。テストも並列実行されるとのことで実行時間短縮にも繋がりそうなのですぐに移行したい。 XCTestは触ったことないが Junit だとできてることが多いので恵まれてるなと思った。 まとめ 以上、「 Google I/O 2024とWWDC24で気になったセッション」を語り合ったTechCafe当日の内容を簡単にまとめさせていただきました。 紹介した以外でもより実践的な事例を紹介したテクニカルセッションや、ハンズオン形式で新しい技術を学べるCodeLabも公式ページにはあるので更に深く学びたい方はぜひご覧いただければと思います。 今回のTechCafeを通じて図らずもAIの最新機種への搭載、開発環境でのコード補完への活用などのトレンド情報に関しては Google と Apple それぞれの特徴や注力ポイントを比較できるような形になりました。 当チームは日頃は各メンバーが各OSに専念して開発することが多いので、そういった面でも自分がよく知っていたり知らなかったりする情報を共有できた非常に有意義なイベントでした。 TechCafeは上記のように勉強会としての効果も高いと思うので、興味を持たれた方は初回開催するまでの道 のりを まとめた以下ブログもご覧いただけますと幸いです。 tech-blog.rakus.co.jp モバイルTechCafeも次回第3回開催を目指してテーマを吟味中ですので、ぜひご参加いただけますと幸いです。
アバター
チームの紹介 チームのミッション チーム体制と役割 チームの文化 取り組み事例 オブジェクトストレージのリプレイス 楽楽精算のインターネット通信で利用される帯域の増加対策 今後の展望 はじめまして。楽楽精算のインフラのマネージャーを務めている永易です。 楽楽精算のインフラチームの組織体系について、現在までと今後についてをお話させていただきます。 チームの紹介 チームのミッション 楽楽精算のインフラを適切なコストで安定させる お客様に楽楽精算を安心して利用していただくために、インフラチームとして安定したサービスの提供を責務としています。 一方、企業として利益を確保する事も必要であり、サービス品質とコスト(売上原価)のバランスを大切にしてます。 チーム体制と役割 現在の楽楽精算インフラメンバーは5人で構成されており、キャリアに合わせてメインの業務を保守運用担当と設計担当に分けています。 具体的な業務内容の内訳としては以下になります。 メンバーのキャリアに合わせて少しずつ設計を担当する領域を増やし、経験を積ませることで思考力や行動力を向上させます。 チームの文化 私たちのチームは、主体的な問題提起をし、改善提案を行うメンバーで構成されています。 楽楽精算は年間成長率(CAGR)30%を超える売上を何年も続けており、2024年3月期には144億4600万を達成しました。 この目まぐるしい成長に伴い、サービスの拡大とともにインフラ規模も拡大してます。大規模なサービスには多角的な視野と技術的な工夫が必要であり、人員の増加を最小限に抑えながらも組織の安定を図るために、メンバーの コンピテンシー (主に思考力、行動力)の成長が重要です。 以下に、当チームのメンバーに求められる具体的な コンピテンシー の一例を示します。 全体を俯瞰する視点を持つ : システム全体を把握し、数年後を予測して問題を多角的に捉えること 類似事象のチェック : 類似事象の分析を通じて、根本原因の特定と解決に繋げる 根本原因の深堀り : 問題の根本原因を追求し、再発防止策を考える これらの コンピテンシー を通じて、「何故その仕事を行うのかを考え、行動できる組織」を目指してます。 取り組み事例 設計分野では、サーバにインストールされているOSの保守終了に伴い、新しいOSへリプレイスする事が作業として多いですが、それ以外に直近1年以内に取り組んできた事例を紹介します。 オブジェクトストレージのリプレイス 楽楽精算はオンプレミス環境でオブジェクトストレージを構築して利用しています。法的要件である「 電子帳簿保存法 」や「 インボイス 制度」の導入に伴い、1顧客あたりのオブジェクトストレージの利用量が急増しました。 その結果、「費用コスト」「サーバ増設コスト」が年間成長率(CAGR)を大きく上回る事が予想されました。 売上に対する原価の大幅な増加による利益低下を懸念し、「増設が簡単」で「ラック収容率が高い」オブジェクトストレージの調査を始めました。 具体的なアクションは以下になります。 要件定義 見積取得 コスト試算 新オブジェクトストレージの技術検証結果から切り替え可能か判断 社内報告とリプレイススケジュール調整 現状コストが高い原因を洗い出し、コスト配分の高い課題を解決すれば全体的に問題が解決する方針で要件定義を進めました( パレートの法則 )。 結果として、 AWS のS3を使うよりも安く、10年後の年間コストが既存環境より数億円のコスト削減が達成し、可用性や性能も向上しました。 楽楽精算のインターネット通信で利用される帯域の増加対策 楽楽精算のサービス拡大に伴い、現在契約しているデータセンターのネットワーク回線プランの帯域では数年後に不足することが予想されました。安定したサービス提供のために帯域を確保しつつ、コストバランスを取るためにデータセンター業者に相談を開始しました。 現在契約しているデータセンター拠点、および別拠点のネットワーク契約プランを調査 3年後までのラック発注数を予測したフォーキャスト資料の作成 データセンター業者への提案と交渉 交渉結果を次年度の予算に反映 課題として、現在契約しているデータセンターには、楽楽精算を安定してサービス提供できるネットワーク帯域契約プランが存在しませんでした。そのため、データセンター業者と協力し、双方にメリットのあるプランを策定する必要がありました。 結果として、新しいプランを策定してもらい、帯域単価コストの削減に成功しました。この成功により、データセンター業者のメンバーと楽楽精算のインフラチームとの交流が続いています。 今後の展望 昨今の サイバー攻撃 の増加に伴い、私たちはセキュリティ対応を強化しています。また、昨年、 AWS のEKS環境を用いて Kubernetes やコンテナ技術をメンバーの一部が習得しました。これらの技術をチーム全体で汎用的に活用できるようにするため、適切な環境と時間を提供し、技術力を生かした設計に取り組んでいます。これにより、運用の効率化や原価の削減を進めています。 これらの技術の積み重ねを通じて、より大規模なネットワーク設計に繋げ、大規模災害対策への道筋を確立していきます。
アバター
はじめに Testcontainersとは Testcontainersのメリット ハンズオン 環境設定 goプロジェクトの作成 必要なパッケージのインストール テストコードの作成 コンテナリクエストの設定 コンテナの起動 コンテナのホストとポートの取得 結果の確認 まとめ はじめに こんにちは! エンジニア2年目のTKDSです! 前回は Dagger を紹介しました。 今回もコンテナ技術を活用して、テストを容易にするツールについて紹介します。 今回取り上げるのは、統合テストやエンドツーエンドテストのためにDockerコンテナを利用するライブラリ、Testcontainersです。 Testcontainersとは Testcontainersはさまざまな プログラミング言語 ( Java 、Go、 Python 、Node.jsなど)向けに提供されており、Daggerと同様にテスト用のコンテナを簡単に作成することができます。 前回の記事で紹介した ユースケース 2と同様のことが実現できるため、テスト内にコンテナの起動コードを直接書くことが可能です。 Testcontainersを使用することでモックを使用せずに外部サービスに依存するテストを書くことが可能になります。 Testcontainersのメリット 次にTestcontainersのメリットについて紹介します。 モックを使わずにテストをかける 前述のようにコンテナでDBなどの外部サービスを用意することでモックに依存しないテストが書けます。 コンテナで用意できる対象は、DBに限らず、MQやNoSQL、Key- value storeなど多岐に渡ります。 事前に用意されている モジュール やコンテナイメージを直接指定してコンテナを作ることができます。 2つ目の方法については後ほど詳しく説明します。 事前に用意されたモジュールがある 前項目で述べたようにTestcontainers moduleが用意されているため、面倒な準備なしに様々な ミドルウェア が使用可能です。 ローカル環境と CI 環境の両方で一貫した環境の用意が可能 コンテナで環境が用意できるため、ローカルでは実行できるのにCIではテストが落ちる、またはその逆など環境依存のテストの不安定さを取り除けます。 参考 - https://testcontainers.com/getting-started/ - https://testcontainers.com/guides/ - https://testcontainers.com/ ハンズオン では、実際にTestcontainersを使ってみます。 今回はGoを使います。 環境設定 筆者の環境 shun@shun-ThinkPad-P14s-Gen-4:~$ cat /etc/os-release PRETTY_NAME="Ubuntu 22.04.4 LTS" NAME="Ubuntu" VERSION_ID="22.04" VERSION="22.04.4 LTS (Jammy Jellyfish)" VERSION_CODENAME=jammy ID=ubuntu ID_LIKE=debian HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" UBUNTU_CODENAME=jammy shun@shun-ThinkPad-P14s-Gen-4:~$ docker version Client: Docker Engine - Community Version: 26.1.3 API version: 1.45 Go version: go1.21.10 Git commit: b72abbb Built: Thu May 16 08:33:29 2024 OS/Arch: linux/amd64 Context: default Server: Docker Engine - Community Engine: Version: 26.1.3 API version: 1.45 (minimum version 1.24) Go version: go1.21.10 Git commit: 8e96db1 Built: Thu May 16 08:33:29 2024 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.6.32 GitCommit: 8b3b7ca2e5ce38e8f31a34f35b2b68ceb8470d89 runc: Version: 1.1.12 GitCommit: v1.1.12-0-g51d5e94 docker-init: Version: 0.19.0 GitCommit: de40ad0 事前にDockerのインストールは済ませておいてください。 goプロジェクトの作成 mkdir go-testcontainers cd go-testcontainers go mod init go-testcontainers 必要なパッケージのインストール go get github.com/testcontainers/testcontainers-go go get github.com/testcontainers/testcontainers-go/modules/postgres go get github.com/jackc/pgx/v4 テストコードの作成 コード全体は github においてあります。 Testcontainersに関わる部分だけ説明します。 今回は事前に用意されたモジュールを使わずにDBを用意します。 コンテナリク エス トの設定 この部分では、コンテナを起動するためのリク エス トを設定しています。 req := testcontainers.ContainerRequest{ Image: "postgres:latest" , ExposedPorts: [] string { "5432/tcp" }, Env: map [ string ] string { "POSTGRES_DB" : "testdb" , "POSTGRES_USER" : "testuser" , "POSTGRES_PASSWORD" : "testpassword" , }, WaitingFor: wait.ForListeningPort( "5432/tcp" ), } Image : 使用するDockerイメージを指定します。ここではpostgres:latestを指定しており、最新の PostgreSQL イメージを使用します。 ExposedPorts : コンテナの公開ポートを指定します。 PostgreSQL はデフォルトで5432ポートを使用するため、5432/ tcp を指定しています。 Env : コンテナ内の 環境変数 を設定します。ここではデータベース名、ユーザー名、パスワードを設定しています。 WaitingFor : コンテナが準備完了になるまで待機する条件を指定します。ここでは、5432ポートがリスニング状態になるのを待ちます。 参考 - https://golang.testcontainers.org/quickstart/ - https://github.com/testcontainers/testcontainers-go/blob/v0.31.0/container.go#L123 コンテナの起動 ここでは、設定したリク エス トに基づいてコンテナを起動しています。 postgresContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: req, Started: true , }) if err != nil { t.Fatal(err) } defer postgresContainer.Terminate(ctx) testcontainers.GenericContainer : 汎用的なコンテナを起動するための関数です。 ctx : コンテキストを渡します。これは操作のキャンセルや タイムアウト を管理するために使用されます。 ContainerRequest : 先ほど設定したコンテナリク エス トを渡します。 Started: true : コンテナがすぐに起動するように指定します。 コンテナのホストとポートの取得 ここでは、起動したコンテナのホストと マッピング されたポートを取得しています。 host, err := postgresContainer.Host(ctx) if err != nil { t.Fatal(err) } port, err := postgresContainer.MappedPort(ctx, "5432" ) if err != nil { t.Fatal(err) } postgresContainer.Host(ctx) : コンテナのホスト名を取得します。通常は localhost になります。 postgresContainer.MappedPort(ctx, "5432") : コンテナ内の5432ポートがホストのどのポートに マッピング されているかを取得します。 結果の確認 実際にテストを実行し、結果を確認してみましょう。 go mod tidy go test -v ./… 無事テストが実行されたことが確認できました! 画像のように、通常のgo testで実行することができ、非常に簡単にDB依存のテストが実行できます。 まとめ 今回はTestcontainersについて紹介しました。 今まではモジュールを使った方法しか知らなかったため、今回のハンズオンで触れてみた内容は新たな学びになりました。 自分でやりたいことを設定できるのであれば、Daggerの代わりに使ってみるのもありかもしれません。 特に、コンテナを用意するだけでCI/CDパイプラインを書かない・Goを使用しない等であれば有力な選択肢になりそうです。 ここまで読んでいただきありがとうございました。
アバター
改善施策を決めるまで 旧アーキテクチャ概要 旧アーキテクチャの問題分析 新アーキテクチャ概要 最後に こんにちは、楽楽販売開発課の岡本です。 弊社では10年を超える長寿プロダクトをいくつも擁していますが、私が担当しているプロダクトもそんな長寿プロダクトの一つです。 さて、どのように優れたプロダクトでも10年以上開発を続けていれば、少なくない量のコード負債を抱えてしまうもので、我々の開発チームでもこの問題に日々悩まされております。 このような状況を打開すべく、昨年9月に開発チーム内に改善専門部隊が立ち上がりました。 本記事では、改善部隊が行った施策の1つである 「バリデーション アーキテクチャ の変更」 を取り上げて紹介しようと思います。 改善施策を決めるまで 先の項でも紹介した通り、我々のプロダクトは少なくない量のコード負債を抱えてしまっています。 ですので、改善部隊が発足時点で改善したい内容はいくらでもあり、正直何を選べば良いのかはっきりとしない状態でした。 このような時に ”感と経験を頼りにピンポイントに改善箇所を見つける” ようなことができれば、手っ取り早いのですが、あいにく私にはそのような技量はないので、まずは開発チームのメンバーが実際にどう感じているのか ヒアリ ングしてみることにしました。 ヒアリ ングの際に注意したのは 「課題を明確にする」 という点です。 課題が明確でないまま ヒアリ ングを行うと方向性が揃わず着地できないことが多いからです。 今回は、「開発速度を上げるには」という課題を設定してメンバーに ヒアリ ングを行い改善の解像度を徐々に上げていきました。 こうして、決定したいくつかの施策のうちの1つが「バリデーション アーキテクチャ の変更」です。 では、事項以降「バリデーション アーキテクチャ の変更」の実施概要にてついて紹介していきます。 旧 アーキテクチャ 概要 まずは、旧 アーキテクチャ の概要を紹介しておきます。 基本的な処理の流れは、以下の図の通りです。 (一部機微な情報が含まれるのでクラス名等は実際のコードから変更を加えています。) 旧 アーキテクチャ の処理フロー 図だけでは、イメージを掴みづらいと思いますので、コード例も載せておきます。 <?php class UserController { /** HTTPリクエストのエンドポイントメソッド */ public function register () : void { // 1.リクエストパラメータを取得 /** * @var array<string, string> $requestParamMap * Note: [name => 'ユーザ氏名', age => 'ユーザ年齢'] */ $ requestParamMap = $ this -> getRequest () -> getParams () ; // 2.リクエストパラメータから バリデーション実行オブジェクト を生成 $ builder = new UserValidationBuilder ( $ requestParamMap ) ; $ validationProcessor = $ builder -> getRegisterValidation () ; // 3.バリデーションを実行して結果出力 if ( !$ validationProcessor -> isValid ()) { echo $ validationProcessor -> getMessage () ; return ; } } } class UserValidationBuilder { /** * @param array<string, string> $requestParamMap * Note: [name => 'ユーザ氏名', age => 'ユーザ年齢'] */ public function __constoracluct ( array $ requestParamMap ) { } public function getRegisterValidation () : ValidationProcessor { // 1. リクエストパラメータとバリデーションのマッピングを指定 $ validationMapping = [ 'name' // $requestParamMap['name'] の値を getNameValidate で指定された内容で検証 => $ this -> getNameValidation ( 'ユーザ氏名' ) , 'age' => $ this -> getAgeValidation ( 'ユーザ年齢' ) ] ; // バリデーション実行オブジェクトを返す return new ValidationProcessor ( $ validationMapping , $ this -> requestParamMap ) ; } private function getNameValidation ( string $ itemName ) : array { // 2. ユーザ氏名のバリデーションを設定 return [ new NotEmptyValidation ( $ itemName ) , // 必須 ] ; } private function getAgeValidation ( string $ itemName ) : array { // 3. ユーザ年齢のバリデーションを設定 return [ new NotEmptyValidation ( $ itemName ) , // 必須 new IsNumberValidation ( $ itemName ) , // 数値入力のみ ] ; } } 旧 アーキテクチャ の問題分析 さて、旧 アーキテクチャ ですがコード例を見てどのように思われたでしょうか? 私は、これを見た瞬間「読みにくいな~」という印象を持ったことを覚えています。 では、なぜ「読みにくい」と感じたのか、これがわからないままでは改善の方針も立てられないので、まず最初にこれの 言語化 を実施しました。 ■実際に 言語化 した内容 リク エス トパラメータが配列で扱われているので、パラメータ追加等の改修で発生する影響度が調査しづらい 対象項目の指定と、その項目のバリデーション内容の指定が、別々の関数で行われており認知負荷が高い (画面をスクロールしないと項目に対するバリデーション内容がわからない) どうでしょうか? 色々と意見もあるかと思いますが、私はこのように 言語化 し、そこから以下ような大方針を立て アーキテクチャ の設計を行うことにしました。 リク エス トパラメータを配列で扱うことをやめる どの項目に、何のバリデーションが実施されるのかを、画面スクロールなしに把握できる状態にする Java で言うところの BeanValidation のようなものを想定 そして、本方針のもとPOCを作成し、更に検討をかさねたすえ、無事新 アーキテクチャ の設計はFIX、昨年11月頃より本格的に導入を開始することができました。 新 アーキテクチャ 概要 では、最終的な新 アーキテクチャ の概要も以下に紹介しておきます。 (旧と同じく処理フロー図とコード例) 新 アーキテクチャ の処理フロー <?php class UserController { /** HTTPリクエストのエンドポイントメソッド */ public function register () : void { // 1.リクエストパラメータをFormに変換 /** * @var array<string, string> $requestParamMap * Note: [name => 'ユーザ氏名', age => 'ユーザ年齢'] */ $ requestParamMap = $ this -> getRequest () -> getParams () ; $ form = new UserRegisterForm ( $ requestParamMap [ 'name' ] , $ requestParamMap [ 'age' ] ) ; // 2.From の内容を検証(バリデーション実行オブジェクトではなく、実行結果が返ってくる) $ result = ValidationBuilder :: validate ( $ form ) ; // 3.結果出力 if ( !$ result -> isValid ) { echo $ result -> message; return ; } } } class UserRegisterForm { public function __construct ( // property と attribute でバリデーションマッピングを再現 // ValidationBuilder がこの定義を取り出して、これまで各自で実装していた ValidationProcessor を自動生成する #[ NotEmpty ( 'ユーザ氏名' )] public ? string $ name , #[ NotEmpty ( 'ユーザ年齢' )] #[ Number ( 'ユーザ年齢' )] public ? int $ age ) { } } 最後に こうして生み出された新 アーキテクチャ ですが、半年ほど置き換え作業を継続し、5月末段階時点で2割程度の完了率となっています。 なにせ、10年越しの負債を解消していっているので、そう易々とは進めさせてもらえないのが現状です。 とはいえ、チーム内から良いフィードバックを多々もらっており、少しづつでも負債解消が進んでいることをメンバーも実感できているようです。 以上、我々のチームの改善取り組みの紹介でした。
アバター