Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
レガシープロダクトの画面部品をUIコンポーネント化 〜駆逐してやる!!このプロダクトから.....
Search
Kohei Y
March 21, 2025
Programming
66
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
レガシープロダクトの画面部品をUIコンポーネント化 〜駆逐してやる!!このプロダクトから... 一匹残らず!!〜
Kohei Y
March 21, 2025
More Decks by Kohei Y
See All by Kohei Y
レガシーコードに潜む奇妙なコメント 〜信じるか信じないかはあなた次第〜
yamamuuu
0
2.2k
不幸を呼び寄せる命名の数々 ~君はそもそも何をされてる方なの?~
yamamuuu
0
2k
Other Decks in Programming
See All in Programming
FreeBSDでZabbixを動かす
kenkino
0
290
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
240
kubernetes コンポーネント開発入門 / 新卒N年目の勉強会&交流会!〜〇〇への誘い〜 #n_study
mazrean
0
240
Webの地図
yosuke_furukawa
PRO
6
4.5k
SONY CISC-NEWS NWS-1750 + NWB-225 フレームバッファの NetBSD/news68k ドライバ実装 / OSC2026Hiroshima
tsutsui
0
110
『寄り添うラジオ』をAIで作る 体験価値から逆算した、会話しないUXと品質設計
theoriatec2024
3
180
Heart of Swift Concurrency
koher
0
790
SREの越境 / SRE Collaboration
y0hgi
0
190
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
480
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
7
2.9k
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
170
スマートフォンでモールス信号を送受信する 〜スマートフォンのLEDとカメラで作る光通信の設計と実装〜
atsuki_seo
0
120
Featured
See All Featured
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
3
4.3k
Designing Experiences People Love
moore
143
24k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Building Adaptive Systems
keathley
44
3.2k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.9k
Code Review Best Practice
trishagee
74
20k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
390
Writing Fast Ruby
sferik
630
63k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
460
Utilizing Notion as your number one productivity tool
mfonobong
4
590
Transcript
© RAKUS Co., Ltd. レガシープロダクトの画⾯部品をUIコンポーネント化 〜駆逐してやる!!このプロダクトから... ⼀匹残らず!!〜 PHPerKaigi 2025 株式会社ラクス
⼭村 光平 2025/03/28 1
⾃⼰紹介 2 • ⼭村光平 • ラクスの新卒3年⽬ • 2024年4⽉にメールディーラーから 楽楽販売へ担当プロダクトが変更 •
業務は実装とかテストとか • 趣味は旅⾏‧テニス‧映画鑑賞
© RAKUS Co., Ltd. 3 技術的負債を返してますか? #PHPerKaigi 2025
© RAKUS Co., Ltd. 4 真摯に向き合ってますか? #PHPerKaigi 2025
© RAKUS Co., Ltd. 5 ちゃんと理解してますか? #PHPerKaigi 2025
© RAKUS Co., Ltd. 6 技術的負債とは #PHPerKaigi 2025
技術的負債 • 将来的な⼿直しにかかる暗黙のコスト • ⾦銭的負債と同様に、返済されなければ「利⼦」が蓄積され 変更の実施が困難になる • プロジェクトを前進させるために必要な場合もある 7 Wikipediaより
Wikipediaより引用:https://ja.wikipedia.org/wiki/%E6%8A%80%E8%A1%93%E7%9A%84%E8%B2%A0%E5%82%B5
技術的負債 • 最初のコードを出荷することは、借⾦をするようなもの • 負債が返済されない場合、コードのために費やされた1分1秒が、 その負債の利息としてカウントされる • 実装の負債の負荷によって、エンジニアリング組織全体が停⽌してしまう 可能性がある -
ウォード・カニンガム、1992年 8 Wikipediaより Wikipediaより引用:https://ja.wikipedia.org/wiki/%E6%8A%80%E8%A1%93%E7%9A%84%E8%B2%A0%E5%82%B5
© RAKUS Co., Ltd. 9 負債である以上返済しなくてはならない #PHPerKaigi 2025
© RAKUS Co., Ltd. 10 バックエンドのロジックだけでなく フロントエンドも例外ではない! #PHPerKaigi 2025
© RAKUS Co., Ltd. 11 PHPで画⾯部品の UIコンポーネント化 #PHPerKaigi 2025
© RAKUS Co., Ltd. 12 なぜUIコンポーネント化? #PHPerKaigi 2025
プロダクトがレガシー 13 • 誕⽣から15年以上経つプロダクト • クラウド型の販売管理システム ◦ 複雑な⾦額計算や請求‧売上計上を⾃動化 楽楽販売について
プロダクトがレガシー 14 • ⾔語:もちろんPHP • フレームワーク:Zend Framework • フロントエンド:ネイティブのJavaScriptとjQuery、フレームワークなし 技術スタック
• 誕⽣から15年以上経つプロダクト • クラウド型の販売管理システム ◦ 複雑な⾦額計算や請求‧売上計上を⾃動化 楽楽販売について
コピペの蔓延、再利⽤性が低い • 15年以上に渡り、静的HTMLの画⾯部品コードがコピペされ続けている • ⾔わずもがな共通化は⾏われていない • 結果として、1画⾯あたりのコード量が巨⼤ • 新画⾯を作成するたび、PhpStormが親の仇の如く「Duplicated Code」を指摘
してくる 15 背景 • コードの可読性を改善し、容易にメンテナンス可能なコード構造を実現する 課題
© RAKUS Co., Ltd. 16 PHPで画⾯部品の UIコンポーネント化 #PHPerKaigi 2025
本セッションについて • UIコンポーネント化のメリット • PHPでコンポーネント化をどのように実装したか • コンポーネントを活⽤してもらうための施策 17 話すこと
本セッションについて • UIコンポーネント化のメリット • PHPでコンポーネント化をどのように実装したか • コンポーネントを活⽤してもらうための施策 18 話すこと •
技術的負債を解消したい⼈(多分全PHPer) • レガシープロダクトから脱却したい⼈(多分ほぼ全PHPer) • フロントエンドのフレームワークを利⽤していない⼈ • 画⾯部品のUIコンポーネント化に興味がある⼈ 対象者
© RAKUS Co., Ltd. 19 UIコンポーネント化とは? #PHPerKaigi 2025
UIコンポーネント化とは • 画⾯部品を独⽴したモジュールとして切り出す • 各部品の機能やスタイルをひとまとめにして共通化 • 他の画⾯でも簡単に利⽤できるように設計 20 ※画⾯部品:画⾯上に配置される具体的な要素(ボタン、ヘッダー、フッターなど)
• 可読性の向上 • メンテナンス性の向上 • 再利⽤性の向上 • テストやバグ修正の効率化 UIコンポーネント化のメリット 21
© RAKUS Co., Ltd. 22 ゴール #PHPerKaigi 2025
ゴール 23 • コピペ⽂化の脱却 ◦ 今後コピペによるコードを駆逐すること • 共通UIコンポーネントの整備 ◦ シンプルな記述で画⾯部品を表⽰でき、複数画⾯で再利⽤可能な
共通コンポーネントを作成する • UIコンポーネントの活⽤推進 ◦ コードの再利⽤を促進する施策を実施し、活⽤を定着させる
© RAKUS Co., Ltd. 24 前提 #PHPerKaigi 2025
前提 25 • フレームワークは使わない
前提 26 • フレームワークは使わない ◦ フレームワークは⽢え
前提 27 • フレームワークは使わない使えない ◦ フレームワークは⽢え
前提 28 • フレームワークは使わない使えない ◦ フレームワークは⽢え ▪ ReactとかVueはUIに変更を加える案件が控えているため無理......
前提 29 • フレームワークは使わない使えない ◦ フレームワークは⽢え ▪ ReactとかVueはUIに変更を加える案件が控えているため無理...... ▪ Laravelとかも検討してるけどすぐには無理......
前提 30 • フレームワークは使わない使えない ◦ フレームワークは⽢え ▪ ReactとかVueはUIに変更を加える案件が控えているため無理...... ▪ Laravelとかも検討してるけどすぐには無理......
• PHPで画⾯部品をコンポーネント化
© RAKUS Co., Ltd. 31 ⽅針 #PHPerKaigi 2025
⽅針 32 1. 画⾯を部品ごとに分解し、各部品のクラスを作成 2. 各画⾯のパーツをファイルに切り出してテンプレート化 3. JavaScriptの利⽤がある場合は汎⽤化して、個別ファイルに切り離す
© RAKUS Co., Ltd. 33 結果 #PHPerKaigi 2025
管理者設定画⾯のタブメニューをコンポーネント化 34 これ →
35 Before(735⾏) タブメニューを表⽰するためのコード
36 TabPanel::show(new Tabs($tabs), $tabMenuList, $this->form?->getTabCategory()); After(1⾏) 表⽰コードはたったの1⾏に!! 管理者設定画⾯のhtml全体の⾏数は805⾏ → 496⾏に削減!
タブメニューを表⽰するためのコード
© RAKUS Co., Ltd. 37 実装の詳細 #PHPerKaigi 2025
画⾯部品を分解し、各部品のクラスを作成 38
画⾯部品を分解し、各部品のクラスを作成 39 Tabsクラス
画⾯部品を分解し、各部品のクラスを作成 40 Tabsクラス Tabクラス
画⾯部品を分解し、各部品のクラスを作成 41 ListGroup クラス
画⾯部品を分解し、各部品のクラスを作成 42 ListGroup クラス LinkListItemクラス
画⾯部品を分解し、各部品のクラスを作成 43 TabPanel クラス
44 クラス設計 TabPanelオブジェクトにTabsとTabMenuList をプロパティで持たせる ※TabMenuListにしているのはListGroup以外 も注⼊されることもあるため TabPanelクラス /** * @param
Tabs $tabs * @param array<string, Component> $tabMenuList * @param string|null $defaultActiveId */ public function __construct( public Tabs $tabs, public array $tabMenuList, public ?string $defaultActiveId = null, ) { parent::__construct(); } TabPanelクラスのコンストラクタ Tabsクラス ListGroupクラス
45 クラス設計 表⽰するメソッド Tabsクラス /** * タブパネルを表示する * * @param
Tabs $tabs * @param array<string, Component> $tabMenuList * @param string|null $defaultActiveId */ public static function show( Tabs $tabs, array $tabMenuList, ?string $defaultActiveId = null ): void { echo ( new self($tabs, $tabMenuList, $defaultActiveId) )->render(); } TabPanelオブジェクトにTabsとTabMenuList をプロパティで持たせる ※TabMenuListにしているのはListGroup以外 も注⼊されることもあるため TabPanelクラス
クラス構成イメージ Tabs Tab Tab Tab Tab
クラス構成イメージ 47 ListGroup LinkListItem LinkListItem LinkListItem
クラス構成イメージ 48 Tabs Tab ListGroup LinkListItem Tab Tab Tab LinkListItem
LinkListItem TabPanel
各パーツをファイルに切り出して、テンプレート化 49 <section> <?php // タブを表示 ?> <?php echo $this->tabs->render()
?> <div> <div> <div> <?php foreach ($this->tabs->tabList as $tab) : ?> <div id="<?php $this->write($tab->id); ?>"> <?php // タブメニューを表示 ?> <?php echo $this->tabMenuList[$tab->id]->render(); ?> </div> <?php endforeach; ?> </div> </div> </div> </section> TabPanel.inc • HTMLをファイルに切り出し
各パーツをファイルに切り出して、テンプレート化 50 <section> <?php // タブを表示 ?> <?php echo $this->tabs->render()
?> <div> <div> <div> <?php foreach ($this->tabs->tabList as $tab) : ?> <div id="<?php $this->write($tab->id); ?>"> <?php // タブメニューを表示 ?> <?php echo $this->tabMenuList[$tab->id]->render(); ?> </div> <?php endforeach; ?> </div> </div> </div> </section> TabPanel.inc • HTMLをincファイルに切り出し • ⼦コンポーネントを利⽤できる 箇所は適宜置き換え Tabsクラス ListGroupクラス
JavaScriptを汎⽤化してファイルに切り出し 51 function tab_action(activeTabId) { $target = $("#" + activeTabId);
$targetTab = $("#t_" + activeTabId); $target.parent().children().hide(); $target.css('display','').show(); $targetTab.parent().children().not(this).removeCl ass('current'); $targetTab.addClass('current'); } tab-panel.js • TabPanelクラスで⽣成された タブパネルに適⽤される
© RAKUS Co., Ltd. 52 プロダクト全体ではどれぐらいの効果が期待できる? #PHPerKaigi 2025
© RAKUS Co., Ltd. 53 パンくずリストのコンポーネントで検証! #PHPerKaigi 2025
パンくずリストのコンポーネントで検証 • 楽楽販売で利⽤されているパンくずリスト数:351箇所 • 前提:表⽰されるパンくずリストは平均3とする • 元のパンくずリスト表⽰のためのコード⾏数:22⾏ • コンポーネント化したパンくずリストの表⽰のためのコード⾏数:わずか5⾏ 54
Breadcrumbs::show([ new Crumb(title: '管理者設定(サンプル) ', url: {url}), new Crumb(title: 'コンポーネント一覧の設定 ', url: {url}), new Crumb(title: 'コンポーネント一覧の設定の設定 '), ]);
結果 55 5967⾏の削減!! ※ 削減⾏数 * パンくずリスト数 htmlファイル全体の3%に相当
© RAKUS Co., Ltd. 56 あとは使うだけ #PHPerKaigi 2025
© RAKUS Co., Ltd. 57 そもそもなぜ⼈はコピペをしてしまうのか #PHPerKaigi 2025
• コンポーネントの存在を知らない なぜ⼈はコピペをしてしまうのか 58
• コンポーネントの存在を知らない • コンポーネントが探しにくい なぜ⼈はコピペをしてしまうのか 59
• コンポーネントの存在を知らない • コンポーネントが探しにくい • コンポーネントの使い⽅が分かりづらい なぜ⼈はコピペをしてしまうのか 60
• コンポーネントの存在を知らない • コンポーネントが探しにくい • コンポーネントの使い⽅が分かりづらい • ⽂化 なぜ⼈はコピペをしてしまうのか 61
• コンポーネントの存在を知らない • コンポーネントが探しにくい • コンポーネントの使い⽅が分かりづらい • ⽂化 なぜ⼈はコピペをしてしまうのか 62
© RAKUS Co., Ltd. 63 コンポーネントを⼀覧で確認できる画⾯を作ろう #PHPerKaigi 2025
コンポーネント⼀覧画⾯の設計 • コンポーネントに何があるか把握できる • イメージはBootstrap • サイドバーでより探しやすく 64 • 各コンポーネントのサンプルコード表⽰
使い⽅が分かりづらい 探しにくい Bootstrapより引用:https://getbootstrap.jp/docs/5.3/components/navs-tabs
完成した⼀覧画⾯ 65
完成した⼀覧画⾯ 66 いい感じ!!
• コンポーネントの存在を知らない ✅ コンポーネントが探しにくい ✅ コンポーネントの使い⽅が分かりづらい • ⽂化 なぜ⼈はコピペをしてしまうのか 67
• コンポーネントの存在を知らない ✅ コンポーネントが探しにくい ✅ コンポーネントの使い⽅が分かりづらい • ⽂化 なぜ⼈はコピペをしてしまうのか 68
⇒ ガイドラインに追加
✅ コンポーネントの存在を知らない ✅ コンポーネントが探しにくい ✅ コンポーネントの使い⽅が分かりづらい ✅ ⽂化 なぜ⼈はコピペをしてしまうのか 69
🎉
既存画⾯のHTMLを画⾯部品に置き換え 今後の展望 • 今後コピペコードが増えることはなくなる • 既存の画⾯は据え置きされている • 既存画⾯の画⾯部品をコンポーネント化 70 •
今回全ての画⾯部品をパーツ化できたわけではない • 随時コンポーネント化していく UIコンポーネントの拡充
PHPでもコンポーネントは作成できる まとめ • フレームワークはなくてもできる! • コードの削減、共通化が可能 • 親コンポーネントに⼦コンポーネントを⼊れ⼦構造で設計すると良き 71 •
可読性の向上 • メンテナンス性の向上 • 再利⽤性の向上 • テストやバグ修正の効率化 コンポーネント化はメリットいっぱい