Slide 1

Slide 1 text

フロントエンドで 良いコードを書くために Sansan株式会社 技術本部 Strategic Products Engineering Unit Contract One Devグループ 井上丈士

Slide 2

Slide 2 text

写真が入ります 井上丈士 Sansan株式会社 技術本部 Strategic Products Engineering Unit Contract One Devグループ zenn: t-keshi twitter: t__keshi 趣味: サウナ駆動技術記事投稿

Slide 3

Slide 3 text

(我々は常に思い悩む) どうしたら良いコードが 書けるようになるだろうか...?🤔

Slide 4

Slide 4 text

知識や経験...?🤔 いや、もう少し具体化しないと コードを良くする方法が見えてこない

Slide 5

Slide 5 text

良いコードを書くための方法を、 以下のように分類・整理することはできないだろうか? そこで、、、 設計原則 フレーム ワークの知識 対話

Slide 6

Slide 6 text

①狭義の設計原則 設計原則

Slide 7

Slide 7 text

設計原則と聞いて、まず頭に浮かぶもののこと。 オニオンアーキテクチャや クリーンアーキテクチャのようなものが挙げられる。 「フロントエンドのクリーンアーキテクチャ」 一時期、流行った、バックエンドのアーキテクチャを輸入する方針 狭義の設計原則

Slide 8

Slide 8 text

設計原則の輸入の問題点

Slide 9

Slide 9 text

オニオンインオニオンを良しとする意見もある。 しかし、0コストで変更容易性が得られるわけではない。 可読性・複雑さとのトレードオフ。 その割に、フロントエンドはフレームワークへの依存が大きく、 どう足掻いても変更はそれほど容易にならない。 オニオンインオニオンの何が駄目か?

Slide 10

Slide 10 text

実装パターンとその背後にある考え方は、区別した方が良さそう。 実装パターンとその背後にある考え方 背後にある考え方 BE実装パターン FE実装パターン

Slide 11

Slide 11 text

例えば責務を意識したレイヤー分け ❌悪い例 データ取得の責務 getUsers()などに切り出すべき 表示の責務 その背後にある考え方? const UsersPage = () => { const [user, setUsers] = useState(null) useEffect(() => { const asyncFn = async () => { const response = axios.get("https://hoge-api/users", { headers: {...省略...} }) return response.data } asyncFn() }, []) return }

Slide 12

Slide 12 text

いわゆるリーダブルコード的なもの。 設計原則に含めていいのか微妙だが、 設計本には、こうした内容も書いてある。 ex.)良いコード悪いコードで学ぶ設計入門 基本的には本の内容をFEにもそのまま適用可能。 JavaScript/TypeScriptでリーダブルなコードを考えるなら、 どんなことが言えるだろうか? 広義の設計原則

Slide 13

Slide 13 text

静的に分岐漏れを検出する。 条件分岐のコツ1 TypeScript 4.9以降 type Action = | { type: "OPEN"; payload: { message: string } } | { type: "CLOSE" } | { type: "TOGGLE" } const reducer = (action: Action) => { switch (action.type) { case "OPEN": return { isOpen: true, message: action.payload.message } case "CLOSE": return { isOpen: false, message: null } default: // TOGGLEがないのでコンパイルエラー throw new Error(action satisfies never) } } TypeScript 4.9以前 type Action = | { type: "OPEN"; payload: { message: string } } | { type: "CLOSE" } | { type: "TOGGLE" } const reducer = (action: Action) => { switch (action.type) { case "OPEN": return { isOpen: true, message: action.payload.message } case "CLOSE": return { isOpen: false, message: null } default: // TOGGLEがないのでコンパイルエラー throw new Error((action as { type: "__invalid__" }).type) } }

Slide 14

Slide 14 text

処理の分岐というより、単純な対応を表す場合は、 Switchの代わりにObjectを使う。 条件分岐のコツ2 type Status = "active" | "inactive" | "sleep" const UserStatus = (status: Status) => { const icon = { active: , inactive: , sleep: }[status] return
{icon}
}

Slide 15

Slide 15 text

RoRoとは、”Receive an Object, Return an Object” オブジェクトで受けてオブジェクトで返すこと RoRo const createUser = (userId: string, userAccountId: string) => { // 省略 } const UserRegistrationDialog = () => { const handleSubmit = (userAccountId: string, userId: string) => {   // 引数を渡し間違える   createUser(userAccountId, userId) } return } Objectを使うと混乱は防げる (他の言語でいう名前付き引数やキーワード引数) const handleSubmit = ({userId, userAccountId}) => { createUser({ userId, userAccountId}) }

Slide 16

Slide 16 text

Gap

Slide 17

Slide 17 text

②フレームワークの知識

Slide 18

Slide 18 text

あまりにもuseEffectが乱用されすぎている。 これはありがちな悲劇。 useEffectはエスケープハッチ、仕方なく使うもの。 useMemoなどで済むようなケースで、 安易にuseEffectを使ってはいけない。 例えばReactだと1

Slide 19

Slide 19 text

余計なFragmentが多すぎる。 些細な問題だが、多発すると可読性を下げる要因に。 nullもstringもnumberも 立派なReactElementであり、FCのReturnType。 例えばReactだと2

Slide 20

Slide 20 text

無闇にStateに入れまくる。 状態管理はシンプルに保つのがキモ。 ❌悪い例 例えばReactだと3 const HogeComponent = () => { const [users, setUsers] = useState() const [admin, setAdmin] = useState() // その他数多くのStateなど, 500行くらい return
// ようやくJSX }

Slide 21

Slide 21 text

(再掲)フロントエンドにはフロントエンドの実装パターンがある。 では、フロントエンドの実装パターンとは何だろう? それは、ある程度、フレームワーク依存になってしまう。 Reactの場合だと、 と<コンポーネント設計> なのではないかと思う。 フレームワークの実装パターン

Slide 22

Slide 22 text

APIの呼び出しはsetLoadingやsetErrorなどのボイラプレートに溢れる これは特にCustomHookを使うべきところ react-useのCustomHookを参考にするのもおすすめ 込み入ったロジックはどんどんCustomHookに切り出していこう CustomHook const HogeComponent = () => { const [state, setState] = useState() …500行くらいあるコード... return ようやくJSX } CustomHookで切り出そう

Slide 23

Slide 23 text

taroさんのLTに続く コンポーネント設計

Slide 24

Slide 24 text

Last Journey

Slide 25

Slide 25 text

③対話

Slide 26

Slide 26 text

コンポーネント、それが一番大事 - 基盤となるUIコンポーネントが不足していると、開発速度が出ない - 良いコンポーネントは、開発のアクセル   そして、そんなコンポーネントを作るために必要なのが、

Slide 27

Slide 27 text

デザインチームとの対話

Slide 28

Slide 28 text

ビジネスサイドとの対話 - ビジネスサイド、開発サイドの相互理解 - いつもそれがうまくいくとは限らないが、チーム全体としてのたしかな進歩につな がる

Slide 29

Slide 29 text

まとめ

Slide 30

Slide 30 text

対話 フレームワークの知識 設計原則 良いコード

Slide 31

Slide 31 text

「なぜ良いコードが書けないんだろう」 悩んだときは、それを各要素に分解し、 各個撃破していくことが大事。 ぼんやりした問題を具体的な要素に分解することさえできれば、 「悩む」のではなく、「考える」ことができる。 今日はそんな話がしたかった。

Slide 32

Slide 32 text

採用情報はこちら https://media.sansan-engineering.com/ 積極採用中!!

Slide 33

Slide 33 text

ありがとうございました!

Slide 34

Slide 34 text

狭義の設計原則 WebフロントエンドでDDDを導入のメリットってあるでしょうか WEBフロントエンドにおけるソフトウェア設計の考察 広義の設計原則 Elegant Patterns in Modern JavaScript フレームワークの基礎知識 You Might Not Need an Effect 参考記事