Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
スピンオフサービス構築で培われた開発ノウハウをご紹介!
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
AkitoTsukahara
March 13, 2023
Programming
200
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
スピンオフサービス構築で培われた開発ノウハウをご紹介!
AkitoTsukahara
March 13, 2023
More Decks by AkitoTsukahara
See All by AkitoTsukahara
『自分のデータだけ見せたい!』を叶える──Laravel × Casbin で複雑権限をスッキリ解きほぐす 25 分
akitotsukahara
2
1.1k
PHP8.2にバージョンアップして もっと型表現を豊かにしよう
akitotsukahara
0
500
オンボーディングのために 私はプロダクト考古学者になりました!
akitotsukahara
3
510
プロダクトチームから他部署に 伝播するふりかえり文化
akitotsukahara
0
550
ビルドツールViteを10分で解説!
akitotsukahara
0
1.3k
今日からSvelteで開発だ! どうする?何から始める?
akitotsukahara
0
330
どのくらい速くなるの?Laravel MixとViteを性能比較してみました!
akitotsukahara
0
11k
スクラムマスターを経験して得られた学びとエンジニアとしての成長
akitotsukahara
0
480
チームでカレーを作ろう!アジャイルカレークッキング
akitotsukahara
1
2.6k
Other Decks in Programming
See All in Programming
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
2
640
The ROI of Quarkus for Spring Boot Applications
hollycummins
0
120
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
280
Claspは野良GASの夢をみるか
takter00
0
190
AIで効率化できた業務・日常
ochtum
0
130
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
240
技術記事、AIに書かせるか、自分で書くか? 〜それでも私が自分の手で書く理由〜 / #QiitaConference
jnchito
2
1.4k
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
230
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.2k
タクシーアプリ『GO』の バックエンド開発のおける AI利活用と若者のすべて
pyama86
3
2k
OSもどきOS
arkw
0
560
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.6k
Featured
See All Featured
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
160
The SEO identity crisis: Don't let AI make you average
varn
0
490
Embracing the Ebb and Flow
colly
88
5.1k
We Have a Design System, Now What?
morganepeng
55
8.2k
Believing is Seeing
oripsolob
1
140
Building a Scalable Design System with Sketch
lauravandoore
463
34k
A Modern Web Designer's Workflow
chriscoyier
698
190k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.3k
Unsuck your backbone
ammeep
672
58k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
480
Git: the NoSQL Database
bkeepers
PRO
432
67k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Transcript
Copyright© M&Aクラウド スピンオフサービス構築で 培われた開発ノウハウをご紹介! PHPerKaigi2023 リジェクトカンファレンス Akito.Tsukahara
Copyright© M&Aクラウド 2 自己紹介 塚原彰仁 AkitoTsukahara 株式会社M&Aクラウド AkitoTsukahara akito_tsukahara
Copyright© M&Aクラウド 昨年2022年11月に 「資金調達クラウド」を リリースしました🎉 3
Copyright© M&Aクラウド スピンオフサービス構築で 培われた開発ノウハウを お伝えします! 4
Copyright© M&Aクラウド この発表で聞けることは? 今日話すこと • スピンオフサービス開発で直面した課題と解決策 ◦ 「サブドメイン」か?「パス」か?後回しにできない仕様決定 ◦ 同じアカウントでPFを行き来できるようにする
◦ 新しいサービスドメインを確立させていくには 今日話さないこと • プロジェクトマネジメントに関するノウハウ
Copyright© M&Aクラウド ざっくりとサービスの紹介 • M&Aクラウド ◦ M&Aクラウドは会社・事業を売却したい売り手と会社・事業を買収したい買い手のマッチン グプラットフォーム ◦ 資金調達することもでき、事業会社からの調達が可能
Copyright© M&Aクラウド 7 ざっくりとサービスの紹介 求人広告のように買い手がM&Aニーズを公開することで、売り手自ら買い手を探せる ダイレクトマッチングにより人に依存しないスケーラビリティを実現 買い手 月額無料 成功報酬 ・
案件報酬はM&A成功報酬のみ ・最低手数料なし ・売り手ソーシングのチャネルが増える ・M&Aニーズを発信するだけで売り手を集客 ・仲介業者を介さずにダイレクトにやり取り可能 ・潜在層にもリーチが可能 手数料無料 売り手 ・買い手のM&Aニーズを自ら調べることが可能 ・仲介業者を介さずにダイレクトにやり取り可能 ・買い手のM&A担当者に直接コンタクトをとれる ・仲介業者を使わないので手数料が無料 買い手のメリット 売り手のメリット ・仲介手数料が無料 〇〇領域の会社を 募集します この会社と一緒に やっていきたい! 1.掲載する 2.オファー M&A・出資ニーズを掲載
Copyright© M&Aクラウド 新サービス「資金調達クラウド」 • 資金調達クラウド ◦ 資金調達目的で登録してくださるユーザーが増加傾向にある ◦ M&Aクラウドで資金調達ができることの知名度が低い ▪
資金調達ユーザー向けのプラットフォームを開発しよう
Copyright© M&Aクラウド 出資企業 資金調達企業 9 資金調達クラウドのサービスフロー 完全無料で出資企業のマッチング(紹介)ができるプラットフォーム 手数料完全無料 1.掲載する 3.資金調達依頼
M&A・出資ニーズを掲載 2.発信する 〇〇領域の会社に 出資したい! この会社から 資金調達を受けたい 【メリット】 出資ニーズを発信するだけで、資 金調達ユーザーから連絡が来る 【メリット】 出資企業の出資ニーズを見ること で、適切なマッチングが可能
Copyright© M&Aクラウド リリースまでの大まかな流れ • 開発スケジュール ◦ PdMとビジネスサイドのすり合わせは3ヶ月程度 ◦ 開発は3ヶ月(7月〜10月末) ◦
リリースは11月1日(必達で!) • スコープ ◦ 新規作成は新プラットフォームの3ページ ▪ リリースに間に合うように調整可能 ◦ 既存プラットフォームと共存できるように機能拡張 ▪ 同じアカウントで資金調達とM&Aの両プラットフォームを利用したい
Copyright© M&Aクラウド リリースまでの大まかな流れ
Copyright© M&Aクラウド 開発における課題と解決策 12
Copyright© M&Aクラウド • サイト構成 ◦ 「サブドメイン」と「パス」どっちで新サービスを用意するのか ▪ この選択で開発作業が大きく変化する ▪ finance.macloud.jpOR
macloud.jp/finance • 同じアカウントでどちらのサービスも利用できる ◦ M&A目的でも後から資金調達に切り替えられるように(その逆も) • 新しいサービスドメインを確立させていく ◦ 既存サービスドメインと中途半端に混ざらないように 開発における課題
Copyright© M&Aクラウド • サイト構成 ◦ 「サブドメイン」と「パス」どっちで新サービスを用意するのか ▪ この選択で開発作業が大きく変化する ▪ finance.macloud.jpOR
macloud.jp/finance • 同じアカウントでどちらのサービスも利用できる ◦ M&A目的でも後から資金調達に切り替えられるように(その逆も) • 新しいサービスドメインを確立させていく ◦ 既存サービスドメインと中途半端に混ざらないように 開発における課題
Copyright© M&Aクラウド (課題・なぜ)サイト構成 • 新しいサービスを「サブドメイン」と「パス」のどちらでリリースするか問題 ◦ サービスの関連性 ◦ ユーザーの認識性 ◦
SEOの影響 この判断はエンジニアチームではなく、経営サイドの判断が必要になる 将来的にプラットフォームをどのように拡大させていくのか、事業構想に直結する
Copyright© M&Aクラウド • 後回しにできない仕様決定である ◦ サブドメインなら ▪ サブドメインによるログインセッション管理 • 同じアカウントでPFを行き来するため
▪ 既存フロントフレームワークへのページ追加だと対応が複雑に(Nuxt.js) • できなくはないが、基本仕様から離れた実装になる • 新しくフロントエンド環境を用意することも検討 ◦ 新しいデプロイフローが必要になる 弊社は「サブドメイン」にする決定をしたので、サブドメイン採用時の対応内容をまとめていきます! (課題・なぜ)サイト構成
Copyright© M&Aクラウド (課題・解決策)サイト構成 サブドメインによるログインセッション管理方法(Laravel) 値をしてしないとnullになるが、 とすることでサブドメインのセッション共通化が行えるようになる 'domain' => env('SESSION_DOMAIN', null),
config/session.php APP_NAME=macloud.jp #一緒に変更する必要あり SESSION_DOMAIN=.macloud.jp .env
Copyright© M&Aクラウド (課題・解決策)サイト構成 この対応でハマったポイント すでにログイン中のユーザーは古いドメイン(サブドメインじゃない)のCookieを保持しているため、 ログインセッションが狂ってしまう。(Cookie名の重複) そのためCookie名を変更する必要がある。その際にログイン中のユーザーは強制ログアウトされてしま うので注意! 'cookie' =>
env('SESSION_COOKIE', str_slug(env('APP_NAME', 'laravel'), '_').'_session'), config/session.php APP_NAME=macloud.jp .env
Copyright© M&Aクラウド (課題・なぜ)サイト構成 • 既存フロントフレームワークへのページ追加だと対応が複雑に(Nuxt.js) • もしも、どちらのサービスにも同じパスが必要になった場合 ◦ macloud.jp/offers ◦
finance.macloud.jp/offers • pages配下にoffersディレクトリは1つしか置けないため、実装できない... → /about →/ Nuxt.jsでは/pagesフォルダ構 成によってルーティングが決 まります。
Copyright© M&Aクラウド (課題・なぜ)サイト構成 • 既存フロントフレームワークへのページ追加だと対応が複雑に(Nuxt.js) ◦ サブドメインの場合 ▪ 基本のルーティング仕様から離れた実装が必要になる ▪
ディレクトリを分けて、モジュールでルーティング機能を拡張する • nuxt-router-module で実装できそうな見込み ◦ パスの場合 ▪ /AAA/mypage, /BBB/mypageとパスを分けるだけで対応できる
Copyright© M&Aクラウド (課題・なぜ)サイト構成 • 別の課題としては、 ◦ ビルドが遅い ◦ 一方のチームとコンフリクトする確率が高い ◦
FeatureFlagの切り替えが増えるほど、if分岐が増えて実装が面倒になる ▪ コードの可読性が下がる ▪ リリース後にコードを削除する手間が増える
Copyright© M&Aクラウド (課題・解決策)サイト構成 • せっかくならフロントフレームワークを新しく用意しよう! ◦ SSRできること ◦ 素早くキャッチアップできること ◦
将来性のあるもの(?) →大事なのは、チームにあったものフレームワークを選択する
Copyright© M&Aクラウド (課題・解決策)サイト構成 詳しくはこちら!
Copyright© M&Aクラウド • サイト構成 ◦ 「サブドメイン」と「パス」どっちで新サービスを用意するのか ▪ この選択で開発作業が大きく変化する ▪ finance.macloud.jp
OR macloud.jp/finance • 同じアカウントでどちらのサービスも利用できる ◦ M&A目的でも後から資金調達に切り替えられるように(その逆も) • 新しいサービスドメインを確立させていく ◦ 既存サービスドメインと中途半端に混ざらないように 開発における課題
Copyright© M&Aクラウド (課題・なぜ)同じアカウントでどちらかのサービスを利用できる • 売却ユーザーは「M&Aクラウド」、調達ユーザーは「資金調達クラウド」 ◦ 売却⇆調達で目的が変わっても同じアカウントで実施したい ◦ 調達して、事業を拡大し、最後にM&AでExitできるようにサポートしたい ◦
ユーザーがどちらのPFを利用しているのか意識することなく、サービスを利用できる ようにしたい • 実現させるには ◦ 新しいログインステータス ◦ 文言の出し分け
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる • 新しいログインステータス ◦ usersテーブルに資金調達ユーザーのフラグ(isFunding)を追加 ▪ 資金調達クラウド経由で登録・変更するとフラグがONに ▪
既存の調達ユーザーにもフラグを付与する ◦ 売り手サービスドメインのエンティティに値オブジェクト(isFunding)を追加することで、 ログイン中の売り手が調達ユーザーかどうか識別できるように
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる • 新しいログインステータス M&Aクラウド ユーザー 資金調達クラウド ユーザー isFunding
ログイン true false
Copyright© M&Aクラウド (課題・なぜ)同じアカウントでどちらかのサービスを利用できる • 文言の出し分け ◦ ログインユーザーのステータスに合わせて表示を切り替える ▪ サイトのヘッダー・フッター ▪
登録情報項目 ▪ メッセージやメールの内容 ◦ ページ ▪ (back)middlewareで出し分けするための変数を設定 ▪ (front)データをフェッチしてページ内で文言の出し分け ◦ メール ▪ Mailableを拡張してユーザー毎に出し分け
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる • 文言の出し分け
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる /** * @var array|string[] * @description ユーザーの資金調達フラグに応じて、資金調達クラウドとして振る舞いたいページを指定する指定はRouteName
*/ protected array $routeNameCheckedByUser = ['AAAApage','BBBBpage']; /** * @param Request $request */ public function handle($request, ¥Closure $next) { if ($this->isIncludeRouteNameCheckedByUser($request)) { $user = $this->authUserHelper->getUser(); if (!is_null($user)) { $this->viewFactory->share( 'serviceAttribute', new ServiceAttribute($user->isFunding()->rawValue()) ); return $next($request); } } } App/Http/Middleware/SetServiceAttribute.php 一部抜粋した実装イメージ
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる class ServiceAttribute { public function __construct(private readonly
bool $isFunding) { } public function isFunding(): bool { return $this->isFunding; } public function getName(): string { return $this->isFunding ? '資金調達クラウド' : 'M&Aクラウド'; } } App/DataTransferObjectServiceAttribute.php 一部抜粋した実装イメージ
Copyright© M&Aクラウド (課題・なぜ)同じアカウントでどちらかのサービスを利用できる • メールの文言の出し分け
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる • メールの文言の出し分け(サービス毎に情報を出し分けする設計) SellerMailable BaseSellerMailable SellingTargetComplete CreationToSeller Mailable
SellerImporta ntMailable SellerMagazin eMailable Laravel 売り手向けメールの 抽象クラス 売り手向けメールの送信 元を定義した 抽象クラス 売り手ユーザーが案件登録し た時に送信するメールのサブ クラス
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる abstract class BaseSellerMailable extends BaseMailable { public
function __construct( public ServiceAttribute $serviceAttribute, ) { } public function serviceNamePrefixSubject(string $title): static { return $this->subject("【 {$this->serviceAttribute->getName()}】 {$title}"); } public function serviceNamePostfixSubject(string $title): static { return $this->subject("{$title}【 {$this->serviceAttribute->getName()}】 "); } } BaseSellerMailable.php 一部抜粋した実装イメージ 出力イメージ 【M&Aクラウド】(メールタイトル) 【資金調達クラウド】(メールタイトル)
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる abstract class SellerMailable extends BaseSellerMailable { public
function __construct( public ServiceAttribute $serviceAttribute, ) { parent::__construct($serviceAttribute); if ($this->serviceAttribute->isFunding()) { $this->from( config('mail.finance.address'), config('mail.finance.name'), ); } else { $this->from( config('mail.from.address'), config('mail.from.name'), ); } } } SellerMailable.php サービスに合わせてメールの ドメインを変更する 一部抜粋した実装イメージ
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる class SellingTargetCompleteCreationToSeller extends SellerMailable { public function
__construct( public AbstractSellingTarget $sellingTarget, public Seller $seller ) { parent::__construct(new ServiceAttribute($seller->getIsFunding()->rawValue())); } public function build(): SellerMailable { $title = $this->serviceAttribute->isFunding() ? '調達情報の入力が完了しました。' : '売却情報の入力が完了し ました。'; return $this ->serviceNamePrefixSubject($title) ->to($this->seller->getEmail()->rawValue()) ->markdown('emails.selling_target.complete_creation.to_seller'); } } SellingTargetCompleteCreationToSeller.php 一部抜粋した実装イメージ メールタイトル、宛先、メー ルテンプレートを用いて生成 する
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる • メールの文言の出し分け
Copyright© M&Aクラウド (課題・解決策)同じアカウントでどちらかのサービスを利用できる この対応でハマったポイント(未来形) • 技術的負債になっていく ◦ 案件を複数化する機能ニーズが高まってきたタイミングで、 負債解消としてリファクタリングが必要になる ▪
パーミッションのような扱いにしてもよかった • パーミッション毎にページを用意する ▪ ログイン基盤の作成 売り手情報にisFunding を持たせている
Copyright© M&Aクラウド • サイト構成 ◦ 「サブドメイン」と「パス」どっちで新サービスを用意するのか ▪ この選択で開発作業が大きく変化する ▪ finance.macloud.jp
OR macloud.jp/finance • 同じアカウントでどちらのサービスも利用できる ◦ M&A目的でも後から資金調達に切り替えられるように(その逆も) • 新しいサービスドメインを確立させていく ◦ 既存サービスドメインと中途半端に混ざらないように 開発における課題
Copyright© M&Aクラウド (課題・なぜ)新しいサービスドメインを確立させていく • サービス毎の情報差分を分けてそれぞれサービスドメインで表現する ◦ 共通部分は継承しつつ、新しい情報は新規サービスドメインで表現 ▪ 出資に関する募集情報を参考に
Copyright© M&Aクラウド (課題・なぜ)新しいサービスドメインを確立させていく • 共通部分は継承しつつ、新しい情報は新規サービスドメインで表現 ◦ サービスを分けることでサービスドメインの重要な情報が変わる ◦ 既存のサービスドメインで対応するとファットクラスになってしまう ▪
2つのサービスで利用するデータを全部持っているクラスが誕生する ◦ 一方のサービスで機能改修時に思わぬ事故が発生したりもする ▪ 不具合を発生させないような設計にしたい
Copyright© M&Aクラウド (課題・なぜ)新しいサービスドメインを確立させていく
Copyright© M&Aクラウド (課題・なぜ)新しいサービスドメインを確立させていく • 共通部分は継承しつつ、新しい情報は新規サービスドメインで表現 Offer 募集情報クラス
Copyright© M&Aクラウド (課題・なぜ)新しいサービスドメインを確立させていく • 共通部分は継承しつつ、新しい情報は新規サービスドメインで表現 BaseOffer 抽象募集クラス AcquisitionOffer InvestmentOffer 買収募集クラス
出資募集クラス
Copyright© M&Aクラウド (課題・なぜ)新しいサービスドメインを確立させていく • 影響範囲があまりも広かったため、一時的に Offer 募集クラス InvestmentOffer 出資募集クラス
Copyright© M&Aクラウド (課題・なぜ)新しいサービスドメインを確立させていく • 影響範囲があまりも広かったため、一時的に ◦ これも技術的負債をいつ返すのかというお話し ▪ 1. 作ったらすぐに返済する
▪ 2. 次の改修前に返済する • 普段の業務効率を著しく悪くするなら1のパターン • そうでなければ2のパターン
Copyright© M&Aクラウド • 技術的に負債について ◦ 財務的に利息と元本が投資の利回りよりも低ければ、負債はポジティブ ◦ ソフトウェアでも同じことが当てはまるはず 開発における課題と解決策 最初に市場へ出るために内部品質を犠牲にしたとしても、より良い内部品質で後から市場に出た
場合よりも、この決定によって得た金額が高ければ、利益を生み出します。 しかし、ある程度不確かなことがあるため、そのような利益を予め見積もるのは難しいので、こ こにはリスクがあると言えます。 引用:InfoQ(技術的負債を管理する)
Copyright© M&Aクラウド 本日のおさらい 48
Copyright© M&Aクラウド まとめ • 「サブドメイン」か?「パス」か? ◦ 両方に対してのメリット・デメリットを用意する • 同じアカウントでPFを行き来できるようにする ◦
「サブドメイン」か「パス」かで難易度が変わってくる ◦ 「サブドメイン」は対応できるのか、できるとしてどれくらいかかるのか調査 ◦ 既存Viewの出し分けは、多少の辛さを覚悟しておく(メール大変だった。。。) • 新しいサービスドメインを確立させていくには ◦ クラス設計においては、適宜分けていく • 技術的負債と投資のバランス、負債の返済タイミング
Copyright© M&Aクラウド 参考資料 • https://tech.macloud.jp/entry/2022/08/30/122131 • https://ymmooot.dev/articles/3/ • https://www.infoq.com/jp/articles/managing-technical-debt/
Copyright© M&Aクラウド ありがとうございました! 51