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
自分がやった設計反省会 / Evaluation of my Architecture
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
ダーシノ
July 21, 2022
Programming
530
0
Share
自分がやった設計反省会 / Evaluation of my Architecture
社内勉強会用
数年前は最適な選択をしたつもりだったが、時が経つにつれツラミが増してきた設計について反省する会。
※ 誰かが悪いとかそういうのではなく、反省して次に活かそうという話です
ダーシノ
July 21, 2022
More Decks by ダーシノ
See All by ダーシノ
がんばりすぎないAI活用 & Tips / Working with AI
bcrikko
0
150
存在感が薄い?!意外とがんばってるさくらインターネットFEチーム / Frontend Conference 2024
bcrikko
1
4.5k
フロントエンドの複雑さに立ち向かう / Tackling Complexity of Front-end Software with DDD and Clean Architecture
bcrikko
19
19k
社内勉強会やっていきガイド / Tips for Sustainable Study Groups
bcrikko
4
2.1k
加速するコンポーネント設計入門 / Component Design as an Accelerator
bcrikko
10
7.2k
コンポーネント指向時代のmargin戦略 / Rethinking the relationship between Components and Margins
bcrikko
1
3.8k
知ってトクするDevToolsの使い方 / DevTools Tips you should know
bcrikko
1
590
伝わるバグ報告 / How to write a better bug report
bcrikko
2
760
Sassの新しいモジュールシステム / Introducing New Sass Module System
bcrikko
0
710
Other Decks in Programming
See All in Programming
Oxlintはいかにしてtsgolintのlint ruleを呼び出しているのか
syumai
0
280
UaaL×Androidアプリのメモリ計測 — Memory Profilerの先へ
rio432
0
160
決定論 vs 確率論:Gemini 3 FlashとTF-IDFを組み合わせた「法規判定エンジン」の構築
shukob
0
170
次世代リンターで探る、tsgo 時代における型認識カスタムルールの現実解
ytakahashii
0
240
Firefoxにコントリビューションして得られた学び
ken7253
2
170
Skillは並べた。動かなかった。契約で繋いだ。— 65個のSkillから、自走する開発サイクルへ
junholee
0
650
20260514_its_the_context_window_stupid.pdf
heita
0
1k
実践ハーネスエンジニアリング:ステアリングループを実例から読み解く / Practical Harness Engineering: Understanding Steering Loops Through Real-World Examples
nrslib
5
5.6k
RailsTokyo 2026#4: AI様があれば、 Hotwireの弱点は消えるか?
naofumi
3
440
AI時代になぜ書くのか
mutsumix
0
430
新規プロダクトを高速で生み出すハーネスエンジニアリング
seanchas116
3
200
🦞OpenClaw works with AWS
licux
1
370
Featured
See All Featured
Optimising Largest Contentful Paint
csswizardry
37
3.7k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
350
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
180
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
190
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.7k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
370
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
430
From π to Pie charts
rasagy
0
180
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
300
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
180
Embracing the Ebb and Flow
colly
88
5k
Transcript
自分でやった設計反省会 その節は、誠に申し訳ございませんでした。 ダーシノ / @bc_rikko
祇 園 精 舎 の 鐘 の 声 諸
行 無 常 の 響 き あ り 娑 羅 双 樹 の 花 の 色 盛 者 必 衰 の 理 を あ ら は す
失敗を共有する理由 成功パターンはさまざまな要因が重なり再現性が低い 失敗パターンはだいたい似ていて再現性が高い
目次 TypeScript/JavaScript Enumの濫用 型定義の誤った共通化 大きすぎるライブラリ(lodash)の導入 フレームワーク 中途半端なコンポーネント化 SFC内はJavaScriptで書く
TypeScript/JavaScript
Enumの濫用
当時の背景 コード内にマジックナンバーや文字列リテラルがあった JavaScript → TypeScript の移行期だった if文、switch文などでtypoに気づけない 定数クラスの代わりにString Enumsを採用した
何が悪かったのか 定数を扱うために String Enums を採用 冗長的で Enum 本来の使い方ではなかった Enum名がつくためコードが長くなった enum
MyStatus { Waiting = 'waiting', Running = 'running', Finished = 'finished' } if (res.data.status === MyStatus.Running) { // ... }
どうすればよかったのか Literal Union Types を使う マジックナンバーなど意味が伝わらりづらいときだけ Enum を使う as const
でもOK // Literal Union Types type MyStatus = 'waiting' | 'running' | 'finished'; if (status === 'running') { /***/ } // String Enums enum StatusCode { OK = 200, Forbidden = 403, NotFound = 404 } if (res.code === StatusCode.NotFound) { /***/ }
型定義の誤った共通化
当時の背景 JavaScriptで実装されたプロジェクトをTypeScriptに移行しようとして いた APIレスポンスの型定義を作りたかった ID , Name , Description ,
... などはほとんど同じだった コード量を減らすために共通化した
何が悪かったのか APIの仕様上、エンドポイントによりスキーマが変わる ひとつにまとめたため、 Optional Properties が大量発生した interface CommonResponse { id:
string scope?: 'public' | 'private' // GET /item のときだけ有効 status?: { availability: string } // GET /status のときだけ有効 } const res: CommonResponse = await fetch(`/item/${id}`) console.log(`scope: ${res.scope}`) // scope: public // Cannot read properties of undefined if (res.status.availability === 'xxx') { /** */ } if (res.status?.availability === 'xxx') { /** */ } // Optional Chaining が必要
どうすればよかったのか 共通化するときは本当に同じモノなのか検討する Union Types を使う( Tagged Union Types も有効) type
ItemResponse = { id: string scope: 'public' | 'private' } type StatusResponse = { id: string status: { availability: MyAvailable } } const res = await fetch<StatusResponse>(`/status/${id}`) if (res.status.availability === 'available') { /** */ }
大きすぎるライブラリの導入
当時の背景 もともと使われていた Prototype.js の代用を探していた IE11やSafariの一部ブラウザで使えないコレクション操作メソッドがあった babel導入前でpolyfillという選択肢がなかった polyfillではなくlodashの導入を選択した
何が悪かったのか 大きすぎてバンドルサイズがモリモリ増えた 今となっては lodash がなくても実装できるようになった 脆弱性報告がときどき来た import * as _
from 'lodash' _.includes(list, 'xxx') _.chain(list).map(...).flat(...).filter(...).values() _.get(item, 'a.b.c')
どうすればよかったのか 「あると便利だけどなくてもなんとかなる」ライブラリは徹底排除 標準仕様を優先する 過去のコードの真似をせず、最新の仕様で考える list.includes('xxx') list.map(...).flat(2).filter(...) item.a?.b?.c
フレームワーク
中途半端なコンポーネント化
当時の背景 Atomic Design の厳密性より、スピードと柔軟性を求めていた コンポーネント粒度が細かいほどバケツリレーになりがちだった よく使うコンポーネント以外は各ページで実装する
何が悪かったのか コンポーネント化する基準が曖昧なままチームメンバーが増えた 同じスタイルを異なるページで使うようになった <!-- Foo.vue --> <div class="item">...</div> <p> Lorem
ipsum dolor sit amet <span class="mute">consectetur</span> </p> <style> .mute { /***/ } </style> <!-- Bar.vue --> <header class="header">...</header> <p> consectetur adipiscing elit <span class="mute">sed do eiusmod</span> </p> <style> /** Foo.vueの .mute と同じスタイル */ .mute { /***/ } </style>
どうすればよかったのか 明確なガイドラインを用意する Atomic Design を採用する痛みはあれどプロジェクトは安定化する Atomic Design でなくてもチーム全体で合意がとれたガイドラインを用意す る <!--
Foo.vue --> <Item>...</Item> <Message> Lorem ipsum dolor sit amet <MuteText class="mute">...</MuteText> </Message> <!-- Bar.vue --> <Header>...</Header> <Message> consectetur adipiscing elit <MuteText class="mute">...</MuteText> </Message>
VueのSFCはJavaScriptで書く
当時の背景 Nuxt@1 系(
[email protected]
)の頃は、TypeScritpのサポートが十分でなかった Class Components 化するよりはJavaScriptで書いたほうが悩みが少な いと思った JSDoc
である程度型をつけられると思った SFC内はJavaScriptで実装した
何が悪かったのか Store 層はTypeScript化して dispatchs / getters にも型をつけた mapヘルパー や computed
を使うことで Store 層の型が全部死んだ JSDoc を書かなかった export default { computed: { items() { return this.$store.getters['items'] || [] } }, methods: { doSomething() { const items = this.items // any } } }
どうすればよかったのか TypeScriptのサポートが充実してきたころにJS→TSに移行する mapヘルパー の利用や getters を computed でラップしない export default
Vue.extend({ methods: { doSomething(): Promise<void> { const items = this.$store.getters['items'] // ^? Item[] } } })
まとめポエム 誰も悪くない。 「最良の方法」だと信じていたし、実際そうだった。 でも、時間が経つにつれ痛みが、 It's so painful. そして、過去の自分の設計を振り返ってこう思う。 お前のいう「絶対」って60%くらいだよな、と。