Upgrade to Pro — share decks privately, control downloads, hide ads and more …

自分がやった設計反省会 / Evaluation of my Architecture

自分がやった設計反省会 / Evaluation of my Architecture

社内勉強会用

数年前は最適な選択をしたつもりだったが、時が経つにつれツラミが増してきた設計について反省する会。
※ 誰かが悪いとかそういうのではなく、反省して次に活かそうという話です

ダーシノ

July 21, 2022
Tweet

More Decks by ダーシノ

Other Decks in Programming

Transcript

  1. 祇 園 精 舎 の 鐘 の 声   諸

    行 無 常 の 響 き あ り 娑 羅 双 樹 の 花 の 色   盛 者 必 衰 の 理 を あ ら は す
  2. 何が悪かったのか 定数を扱うために String Enums を採用 冗長的で Enum 本来の使い方ではなかった Enum名がつくためコードが長くなった enum

    MyStatus { Waiting = 'waiting', Running = 'running', Finished = 'finished' } if (res.data.status === MyStatus.Running) { // ... }
  3. どうすればよかったのか 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) { /***/ }
  4. 何が悪かったのか 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 が必要
  5. どうすればよかったのか 共通化するときは本当に同じモノなのか検討する 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') { /** */ }
  6. 何が悪かったのか コンポーネント化する基準が曖昧なままチームメンバーが増えた 同じスタイルを異なるページで使うようになった <!-- 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>
  7. どうすればよかったのか 明確なガイドラインを用意する 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>
  8. 何が悪かったのか Store 層はTypeScript化して dispatchs / getters にも型をつけた mapヘルパー や computed

    を使うことで Store 層の型が全部死んだ JSDoc を書かなかった export default { computed: { items() { return this.$store.getters['items'] || [] } }, methods: { doSomething() { const items = this.items // any } } }